git.iko.soy/typeable/pandoc
on master help sign in
Extensive changes stemming from a rethinking of the Pandoc data

structure. Key and Note blocks have been removed. Link and image URLs are now stored directly in Link and Image inlines, and note blocks are stored in Note inlines. This requires changes in both parsers and writers. Markdown and RST parsers need to extract data from key and note blocks and insert them into the relevant inline elements. Other parsers can be simplified, since there is no longer any need to construct separate key and note blocks. Markdown, RST, and HTML writers need to construct lists of notes; Markdown and RST writers need to construct lists of link references (when the --reference-links option is specified); and the RST writer needs to construct a list of image substitution references. All writers have been rewritten to use the State monad when state is required. This rewrite yields a small speed boost and considerably cleaner code. * Text/Pandoc/Definition.hs: + blocks: removed Key and Note + inlines: removed NoteRef, added Note + modified Target: there is no longer a 'Ref' target; all targets are explicit URL, title pairs * Text/Pandoc/Shared.hs: + Added 'Reference', 'isNoteBlock', 'isKeyBlock', 'isLineClump', used in some of the readers. + Removed 'generateReference', 'keyTable', 'replaceReferenceLinks', 'replaceRefLinksBlockList', along with some auxiliary functions used only by them. These are no longer needed, since reference links are resolved in the Markdown and RST readers. + Moved 'inTags', 'selfClosingTag', 'inTagsSimple', and 'inTagsIndented' to the Docbook writer, since that is now the only module that uses them. + Changed name of 'escapeSGMLString' to 'escapeStringForXML' + Added KeyTable and NoteTable types + Removed fields from ParserState; 'stateKeyBlocks', 'stateKeysUsed', 'stateNoteBlocks', 'stateNoteIdentifiers', 'stateInlineLinks'. Added 'stateKeys' and 'stateNotes'. + Added clause for Note to 'prettyBlock'. + Added 'writerNotes', 'writerReferenceLinks' fields to WriterOptions. * Text/Pandoc/Entities.hs: Renamed 'escapeSGMLChar' and 'escapeSGMLString' to 'escapeCharForXML' and 'escapeStringForXML' * Text/ParserCombinators/Pandoc.hs: Added lineClump parser: parses a raw line block up to and including following blank lines. * Main.hs: Replaced --inline-links with --reference-links. * README: + Documented --reference-links and removed description of --inline-links. + Added note that footnotes may occur anywhere in the document, but must be at the outer level, not embedded in block elements. * man/man1/pandoc.1, man/man1/html2markdown.1: Removed --inline-links option, added --reference-links option * Markdown and RST readers: + Rewrote to fit new Pandoc definition. Since there are no longer Note or Key blocks, all note and key blocks are parsed on a first pass through the document. Once tables of notes and keys have been constructed, the remaining parts of the document are reassembled and parsed. + Refactored link parsers. * LaTeX and HTML readers: Rewrote to fit new Pandoc definition. Since there are no longer Note or Key blocks, notes and references can be parsed in a single pass through the document. * RST, Markdown, and HTML writers: Rewrote using state monad new Pandoc and definition. State is used to hold lists of references footnotes to and be printed at the end of the document. * RTF and LaTeX writers: Rewrote using new Pandoc definition. (Because of the different treatment of footnotes, the "notes" parameter is no longer needed in the block and inline conversion functions.) * Docbook writer: + Moved the functions 'attributeList', 'inTags', 'selfClosingTag', 'inTagsSimple', 'inTagsIndented' from Text/Pandoc/Shared, since they are now used only by the Docbook writer. + Rewrote using new Pandoc definition. (Because of the different treatment of footnotes, the "notes" parameter is no longer needed in the block and inline conversion functions.) * Updated test suite * Throughout: old haskell98 module names replaced by hierarchical module names, e.g. List by Data.List. * debian/control: Include libghc6-xhtml-dev instead of libghc6-html-dev in "Build-Depends." * cabalize: + Remove haskell98 from BASE_DEPENDS (since now the new hierarchical module names are being used throughout) + Added mtl to BASE_DEPENDS (needed for state monad) + Removed html from GHC66_DEPENDS (not needed since xhtml is now used) git-svn-id: https://pandoc.googlecode.com/svn/trunk@580 788f1e2b-df1e-0410-8736-df70ead52e1b

commit23df0ed1768c4489d41180e145e98a37fd4ac9fc authorfiddlosopher <fiddlosopher@788f1e2b-df1e-0410-8736-df70ead52e1b> dateTue 10 Apr 2007, 01:56 (20 years ago) parent74e7497
26 files changed+1232−1433
README+7−3 cabalize+2−2 debian/control+1−1 man/man1/html2markdown.1+3−2 man/man1/pandoc.1+3−2 src/Main.hs+10−11 src/Text/Pandoc/Definition.hs+6−12 src/Text/Pandoc/Entities.hs+15−15 src/Text/Pandoc/Readers/HTML.hs+5−14 src/Text/Pandoc/Readers/LaTeX.hs+7−16 src/Text/Pandoc/Readers/Markdown.hs+94−123 src/Text/Pandoc/Readers/RST.hs+66−64 src/Text/Pandoc/Shared.hs+39−188 src/Text/Pandoc/Writers/Docbook.hs+60−35 src/Text/Pandoc/Writers/HTML.hs+152−137 src/Text/Pandoc/Writers/LaTeX.hs+57−76 src/Text/Pandoc/Writers/Markdown.hs+204−144 src/Text/Pandoc/Writers/RST.hs+233−192 src/Text/Pandoc/Writers/RTF.hs+58−79 src/Text/ParserCombinators/Pandoc.hs+10−2 tests/html-reader.native+33−53 tests/rst-reader.native+8−14 tests/testsuite.native+36−62 tests/writer.markdown+26−41 tests/writer.native+36−62 tests/writer.rst+61−83
README+7−3
@@ -241,8 +241,8 @@ preserved, rather than converted to spaces (the default).
241241`--strict` specifies that strict markdown syntax is to be used, without
242242pandoc's usual extensions and variants (described below).
243243
244−`--inline-links` causes links in HTML to be parsed as inline links, rather
245−than reference links.
244+`--reference-links` causes reference-style links to be used in markdown
245+and reStructuredText output. By default inline links are used.
246246
247247`-R` or `--parse-raw` causes the HTML and LaTeX readers to parse HTML
248248codes and LaTeX environments that it can't translate as raw HTML or
@@ -498,13 +498,17 @@ Pandoc's markdown allows footnotes, using the following syntax:
498498 In this way, multi-paragraph footnotes work just like
499499 multi-paragraph list items in markdown.
500500
501− This paragraph won't be part of the note.
501+ This paragraph won't be part of the note, because it isn't indented.
502502
503503The identifiers in footnote references may not contain spaces, tabs,
504504or newlines. These identifiers are used only to correlate the
505505footnote reference with the note itself; in the output, footnotes
506506will be numbered sequentially.
507507
508+The footnotes themselves need not be placed at the end of the
509+document. They may appear anywhere except inside other block elements
510+(lists, block quotes, tables, etc.).
511+
508512Inline footnotes are also allowed (though, unlike regular notes,
509513they cannot contain multiple paragraphs). The syntax is as follows:
510514
cabalize+2−2
@@ -1,10 +1,10 @@
11#!/bin/sh
22# Preprocesses cabal file.
33
4−BASE_DEPENDS="base haskell98 parsec xhtml"
4+BASE_DEPENDS="base parsec xhtml mtl"
55
66GHC64_DEPENDS=${GHC64_DEPENDS}
7−GHC66_DEPENDS=${GHC66_DEPENDS-"regex-compat html"}
7+GHC66_DEPENDS=${GHC66_DEPENDS-"regex-compat"}
88HCFLAGS=${HCFLAGS-"-O0"}
99
1010set -- $(ghc --version)
debian/control+1−1
@@ -2,7 +2,7 @@ Source: pandoc
22Section: text
33Priority: optional
44Maintainer: Recai Oktaş <roktas@debian.org>
5−Build-Depends: debhelper (>= 4.0.0), haskell-devscripts (>=0.5.12), ghc6 (>= 6.6-1), libghc6-html-dev (>= 1.0-1), perl
5+Build-Depends: debhelper (>= 4.0.0), haskell-devscripts (>=0.5.12), ghc6 (>= 6.6-1), libghc6-xhtml-dev (>= 2006.9.13-3), perl
66Build-Depends-Indep: haddock
77Standards-Version: 3.7.2.0
88
man/man1/html2markdown.1+3−2
@@ -32,8 +32,9 @@ Write output to \fIFILE\fR instead of STDOUT.
3232.B \-\-strict
3333Use strict markdown syntax, with no extensions or variants.
3434.TP
35−.B \-\-inline\-links
36−Parse links in HTML as inline links, rather than reference links.
35+.B \-\-reference\-links
36+Use reference-style links, rather than inline links, in writing markdown
37+or reStructuredText.
3738.TP
3839.B \-R, \-\-parse-raw
3940Parse untranslatable HTML codes as raw HTML.
man/man1/pandoc.1+3−2
@@ -105,8 +105,9 @@ Specify tab stop (default is 4).
105105.B \-\-strict
106106Use strict markdown syntax, with no extensions or variants.
107107.TP
108−.B \-\-inline\-links
109−Parse links in HTML as inline links, rather than reference links.
108+.B \-\-reference\-links
109+Use reference-style links, rather than inline links, in writing markdown
110+or reStructuredText.
110111.TP
111112.B \-R, \-\-parse-raw
112113Parse untranslatable HTML codes and LaTeX environments as raw HTML
src/Main.hs+10−11
@@ -55,7 +55,7 @@ import System.Console.GetOpt
5555import System.IO
5656import Data.Maybe ( fromMaybe )
5757import Data.List ( isPrefixOf )
58−import Char ( toLower )
58+import Data.Char ( toLower )
5959import Control.Monad ( (>>=) )
6060
6161version :: String
@@ -118,7 +118,7 @@ data Opt = Opt
118118 , optDumpArgs :: Bool -- ^ Output command-line arguments
119119 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
120120 , optStrict :: Bool -- ^ Use strict markdown syntax
121− , optInlineLinks :: Bool -- ^ Use inline links in parsing HTML
121+ , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
122122 }
123123
124124-- | Defaults for command-line options.
@@ -144,7 +144,7 @@ defaultOpts = Opt
144144 , optDumpArgs = False
145145 , optIgnoreArgs = False
146146 , optStrict = False
147− , optInlineLinks = False
147+ , optReferenceLinks = False
148148 }
149149
150150-- | A list of functions, each transforming the options data structure
@@ -190,10 +190,10 @@ options =
190190 (\opt -> return opt { optStrict = True } ))
191191 "" -- "Use strict markdown syntax with no extensions"
192192
193− , Option "" ["inline-links"]
193+ , Option "" ["reference-links"]
194194 (NoArg
195− (\opt -> return opt { optInlineLinks = True } ))
196− "" -- "Use inline links in parsing HTML"
195+ (\opt -> return opt { optReferenceLinks = True } ))
196+ "" -- "Use reference links in parsing HTML"
197197
198198 , Option "R" ["parse-raw"]
199199 (NoArg
@@ -405,7 +405,7 @@ main = do
405405 , optDumpArgs = dumpArgs
406406 , optIgnoreArgs = ignoreArgs
407407 , optStrict = strict
408− , optInlineLinks = inlineLinks
408+ , optReferenceLinks = referenceLinks
409409 } = opts
410410
411411 if dumpArgs
@@ -453,8 +453,7 @@ main = do
453453 stateStandalone = standalone && (not strict),
454454 stateSmart = smart || writerName' == "latex",
455455 stateColumns = columns,
456− stateStrict = strict,
457− stateInlineLinks = inlineLinks }
456+ stateStrict = strict }
458457 let csslink = if (css == "")
459458 then ""
460459 else "<link rel=\"stylesheet\" href=\"" ++ css ++
@@ -469,13 +468,13 @@ main = do
469468 writerHeader = header,
470469 writerTitlePrefix = titlePrefix,
471470 writerTabStop = tabStop,
472− writerNotes = [],
473471 writerS5 = (writerName=="s5"),
474472 writerIncremental = incremental,
475473 writerNumberSections = numberSections,
476474 writerIncludeBefore = includeBefore,
477475 writerIncludeAfter = includeAfter,
478− writerStrictMarkdown = strict }
476+ writerStrictMarkdown = strict,
477+ writerReferenceLinks = referenceLinks }
479478
480479 (readSources sources) >>= (hPutStr output . encodeUTF8 .
481480 (writer writerOptions) .
src/Text/Pandoc/Definition.hs+6−12
@@ -50,7 +50,6 @@ data Block
5050 = Plain [Inline] -- ^ Plain text, not a paragraph
5151 | Null -- ^ Nothing
5252 | Para [Inline] -- ^ Paragraph
53− | Key [Inline] Target -- ^ Reference key: name (inlines) and 'Target'
5453 | CodeBlock String -- ^ Code block (literal)
5554 | RawHtml String -- ^ Raw HTML block (literal)
5655 | BlockQuote [Block] -- ^ Block quote (list of blocks)
@@ -63,24 +62,18 @@ data Block
6362 -- the term, and a block list)
6463 | Header Int [Inline] -- ^ Header - level (integer) and text (inlines)
6564 | HorizontalRule -- ^ Horizontal rule
66− | Note String [Block] -- ^ Footnote or endnote - reference (string),
67− -- text (list of blocks)
6865 | Table [Inline] [Alignment] [Float] [[Block]] [[[Block]]] -- ^ Table,
6966 -- with caption, column alignments,
7067 -- relative column widths, column headers
7168 -- (each a list of blocks), and rows
7269 -- (each a list of lists of blocks)
7370 deriving (Eq, Read, Show)
74−
75−-- | Target for a link: either a URL or an indirect (labeled) reference.
76−data Target
77− = Src String String -- ^ First string is URL, second is title
78− | Ref [Inline] -- ^ Label (list of inlines) for an indirect ref
79− deriving (Show, Eq, Read)
8071
8172-- | Type of quotation marks to use in Quoted inline.
8273data QuoteType = SingleQuote | DoubleQuote deriving (Show, Eq, Read)
8374
75+type Target = (String, String) -- ^ Link target (URL, title)
76+
8477-- | Inline elements.
8578data Inline
8679 = Str String -- ^ Text (string)
@@ -96,8 +89,9 @@ data Inline
9689 | LineBreak -- ^ Hard line break
9790 | TeX String -- ^ LaTeX code (literal)
9891 | HtmlInline String -- ^ HTML code (literal)
99− | Link [Inline] Target -- ^ Hyperlink: text (list of inlines) and target
100− | Image [Inline] Target -- ^ Image: alternative text (list of inlines)
92+ | Link [Inline] Target -- ^ Hyperlink: text (list of inlines), target
93+ | Image [Inline] Target -- ^ Image: alt text (list of inlines), target
10194 -- and target
102− | NoteRef String -- ^ Footnote or endnote reference
95+ | Note [Block] -- ^ Footnote or endnote - reference (string),
96+ -- text (list of blocks)
10397 deriving (Show, Eq, Read)
src/Text/Pandoc/Entities.hs+15−15
@@ -32,8 +32,8 @@ module Text.Pandoc.Entities (
3232 charToEntity,
3333 charToNumericalEntity,
3434 decodeEntities,
35− escapeSGMLChar,
36− escapeSGMLString,
35+ escapeCharForXML,
36+ escapeStringForXML,
3737 characterEntity
3838 ) where
3939import Data.Char ( chr, ord )
@@ -49,11 +49,11 @@ charToEntity char = Map.findWithDefault (charToNumericalEntity char) char revers
4949charToNumericalEntity :: Char -> String
5050charToNumericalEntity ch = "&#" ++ show (ord ch) ++ ";"
5151
52−-- | Parse SGML character entity.
52+-- | Parse character entity.
5353characterEntity :: GenParser Char st Char
54−characterEntity = namedEntity <|> hexEntity <|> decimalEntity <?> "SGML entity"
54+characterEntity = namedEntity <|> hexEntity <|> decimalEntity <?> "character entity"
5555
56−-- | Parse SGML character entity.
56+-- | Parse character entity.
5757namedEntity :: GenParser Char st Char
5858namedEntity = try $ do
5959 st <- char '&'
@@ -62,7 +62,7 @@ namedEntity = try $ do
6262 let entity = "&" ++ body ++ ";"
6363 return $ Map.findWithDefault '?' entity entityTable
6464
65−-- | Parse SGML hexadecimal entity.
65+-- | Parse hexadecimal entity.
6666hexEntity :: GenParser Char st Char
6767hexEntity = try $ do
6868 st <- string "&#"
@@ -71,7 +71,7 @@ hexEntity = try $ do
7171 end <- char ';'
7272 return $ chr $ read ('0':'x':body)
7373
74−-- | Parse SGML decimal entity.
74+-- | Parse decimal entity.
7575decimalEntity :: GenParser Char st Char
7676decimalEntity = try $ do
7777 st <- string "&#"
@@ -79,9 +79,9 @@ decimalEntity = try $ do
7979 end <- char ';'
8080 return $ chr $ read body
8181
82−-- | Escape one character as needed for SGML.
83−escapeSGMLChar :: Char -> String
84−escapeSGMLChar x =
82+-- | Escape one character as needed for XML.
83+escapeCharForXML :: Char -> String
84+escapeCharForXML x =
8585 case x of
8686 '&' -> "&amp;"
8787 '<' -> "&lt;"
@@ -94,13 +94,13 @@ escapeSGMLChar x =
9494needsEscaping :: Char -> Bool
9595needsEscaping c = c `elem` "&<>\"\160"
9696
97−-- | Escape string as needed for SGML. Entity references are not preserved.
98−escapeSGMLString :: String -> String
99−escapeSGMLString "" = ""
100−escapeSGMLString str =
97+-- | Escape string as needed for XML. Entity references are not preserved.
98+escapeStringForXML :: String -> String
99+escapeStringForXML "" = ""
100+escapeStringForXML str =
101101 case break needsEscaping str of
102102 (okay, "") -> okay
103− (okay, (c:cs)) -> okay ++ escapeSGMLChar c ++ escapeSGMLString cs
103+ (okay, (c:cs)) -> okay ++ escapeCharForXML c ++ escapeStringForXML cs
104104
105105-- | Convert entities in a string to characters.
106106decodeEntities :: String -> String
src/Text/Pandoc/Readers/HTML.hs+5−14
@@ -45,7 +45,7 @@ import Text.ParserCombinators.Pandoc
4545import Text.Pandoc.Definition
4646import Text.Pandoc.Shared
4747import Text.Pandoc.Entities ( characterEntity, decodeEntities )
48−import Maybe ( fromMaybe )
48+import Data.Maybe ( fromMaybe )
4949import Data.List ( intersect, takeWhile, dropWhile )
5050import Data.Char ( toUpper, toLower, isAlphaNum )
5151
@@ -267,9 +267,7 @@ parseHtml = do
267267 option "" (htmlEndTag "html")
268268 many anyChar -- ignore anything after </html>
269269 eof
270− state <- getState
271− let keyBlocks = stateKeyBlocks state
272− return (Pandoc (Meta title authors date) (blocks ++ (reverse keyBlocks)))
270+ return (Pandoc (Meta title authors date) blocks)
273271
274272--
275273-- parsing blocks
@@ -456,11 +454,7 @@ link = try $ do
456454 Nothing -> fail "no href"
457455 let title = fromMaybe "" (extractAttribute "title" attributes)
458456 label <- inlinesTilEnd "a"
459− state <- getState
460− ref <- if stateInlineLinks state
461− then return (Src url title)
462− else generateReference url title
463− return $ Link (normalizeSpaces label) ref
457+ return $ Link (normalizeSpaces label) (url, title)
464458
465459image = try $ do
466460 (tag, attributes) <- htmlTag "img"
@@ -469,8 +463,5 @@ image = try $ do
469463 Nothing -> fail "no src"
470464 let title = fromMaybe "" (extractAttribute "title" attributes)
471465 let alt = fromMaybe "" (extractAttribute "alt" attributes)
472− state <- getState
473− ref <- if stateInlineLinks state
474− then return (Src url title)
475− else generateReference url title
476− return $ Image [Str alt] ref
466+ return $ Image [Str alt] (url, title)
467+
src/Text/Pandoc/Readers/LaTeX.hs+7−16
@@ -37,8 +37,8 @@ import Text.ParserCombinators.Parsec
3737import Text.ParserCombinators.Pandoc
3838import Text.Pandoc.Definition
3939import Text.Pandoc.Shared
40−import Maybe ( fromMaybe )
41−import Char ( chr )
40+import Data.Maybe ( fromMaybe )
41+import Data.Char ( chr )
4242
4343-- | Parse LaTeX from string and return 'Pandoc' document.
4444readLaTeX :: ParserState -- ^ Parser state, including options for parser
@@ -135,14 +135,11 @@ parseLaTeX = do
135135 spaces
136136 eof
137137 state <- getState
138− let keyBlocks = stateKeyBlocks state
139− let noteBlocks = stateNoteBlocks state
140138 let blocks' = filter (/= Null) blocks
141139 let title' = stateTitle state
142140 let authors' = stateAuthors state
143141 let date' = stateDate state
144− return (Pandoc (Meta title' authors' date')
145− (blocks' ++ (reverse noteBlocks) ++ (reverse keyBlocks)))
142+ return (Pandoc (Meta title' authors' date') blocks')
146143
147144--
148145-- parsing blocks
@@ -618,15 +615,15 @@ link = try (do
618615 url <- manyTill anyChar (char '}')
619616 char '{'
620617 label <- manyTill inline (char '}')
621− return (Link (normalizeSpaces label) (Src url "")))
618+ return (Link (normalizeSpaces label) (url, "")))
622619
623620image = try (do
624621 ("includegraphics", _, args) <- command
625622 let args' = filter isArg args -- filter out options
626623 let src = if null args' then
627− Src "" ""
624+ ("", "")
628625 else
629− Src (stripFirstAndLast (head args')) ""
626+ (stripFirstAndLast (head args'), "")
630627 return (Image [Str "image"] src))
631628
632629footnote = try (do
@@ -640,13 +637,7 @@ footnote = try (do
640637 setInput $ contents'
641638 blocks <- parseBlocks
642639 setInput rest
643− state <- getState
644− let notes = stateNoteBlocks state
645− let nextRef = case notes of
646− [] -> "1"
647− (Note ref body):rest -> (show ((read ref) + 1))
648− setState (state { stateNoteBlocks = (Note nextRef blocks):notes })
649− return (NoteRef nextRef))
640+ return (Note blocks))
650641
651642-- | Parse any LaTeX command and return it in a raw TeX inline element.
652643rawLaTeXInline :: GenParser Char ParserState Inline
src/Text/Pandoc/Readers/Markdown.hs+94−123
@@ -31,7 +31,7 @@ module Text.Pandoc.Readers.Markdown (
3131 readMarkdown
3232 ) where
3333
34−import Data.List ( findIndex, sortBy, transpose, isSuffixOf, intersect )
34+import Data.List ( findIndex, sortBy, transpose, isSuffixOf, intersect, lookup )
3535import Data.Char ( isAlphaNum )
3636import Text.ParserCombinators.Pandoc
3737import Text.Pandoc.Definition
@@ -160,28 +160,72 @@ titleBlock = try (do
160160 option "" blanklines
161161 return (title, author, date))
162162
163−-- | Returns the number assigned to a Note block
164−numberOfNote :: Block -> Int
165−numberOfNote (Note ref _) = (read ref)
166−numberOfNote _ = 0
167−
168163parseMarkdown = do
169− updateState (\state -> state { stateParseRaw = True })
170− -- need to parse raw HTML, since markdown allows it
164+ updateState (\state -> state { stateParseRaw = True }) -- parse raw HTML: markdown allows it
171165 (title, author, date) <- option ([],[],"") titleBlock
172166 -- go through once just to get list of reference keys
173− keysUsed <- lookAhead $ (do {manyTill (referenceKey <|> (do{anyLine; return Null})) eof;
174− newState <- getState;
175− return $ stateKeysUsed newState})
176− updateState (\st -> st { stateKeysUsed = keysUsed })
167+ refs <- manyTill (noteBlock <|> referenceKey <|> (do l <- lineClump
168+ return (LineClump l))) eof
169+ let keys = map (\(KeyBlock label target) -> (label, target)) $
170+ filter isKeyBlock refs
171+ let notes = map (\(NoteBlock label blocks) -> (label, blocks)) $
172+ filter isNoteBlock refs
173+ let rawlines = map (\(LineClump ln) -> ln) $ filter isLineClump refs
174+ setInput $ concat rawlines -- with note blocks and keys stripped out
175+ updateState (\state -> state { stateKeys = keys, stateNotes = notes })
177176 blocks <- parseBlocks -- go through again, for real
178177 let blocks' = filter (/= Null) blocks
179− state <- getState
180− let keys = reverse $ stateKeyBlocks state
181− let notes = reverse $ stateNoteBlocks state
182− let sortedNotes = sortBy (\x y -> compare (numberOfNote x)
183− (numberOfNote y)) notes
184− return (Pandoc (Meta title author date) (blocks' ++ sortedNotes ++ keys))
178+ return (Pandoc (Meta title author date) blocks')
179+
180+--
181+-- initial pass for references
182+--
183+
184+referenceKey = try $ do
185+ nonindentSpaces
186+ label <- reference
187+ char labelSep
188+ skipSpaces
189+ option ' ' (char autoLinkStart)
190+ src <- many (noneOf (titleOpeners ++ [autoLinkEnd] ++ endLineChars))
191+ option ' ' (char autoLinkEnd)
192+ tit <- option "" title
193+ blanklines
194+ return $ KeyBlock label (removeTrailingSpace src, tit)
195+
196+noteMarker = try (do
197+ char labelStart
198+ char noteStart
199+ manyTill (noneOf " \t\n") (char labelEnd))
200+
201+rawLine = try (do
202+ notFollowedBy' blankline
203+ notFollowedBy' noteMarker
204+ contents <- many1 nonEndline
205+ end <- option "" (do
206+ newline
207+ option "" (try indentSpaces)
208+ return "\n")
209+ return (contents ++ end))
210+
211+rawLines = do
212+ lines <- many1 rawLine
213+ return (concat lines)
214+
215+noteBlock = try $ do
216+ failIfStrict
217+ ref <- noteMarker
218+ char ':'
219+ option ' ' (try blankline)
220+ option "" (try indentSpaces)
221+ raw <- sepBy rawLines (try (do {blankline; indentSpaces}))
222+ option "" blanklines
223+ -- parse the extracted text, which may contain various block elements:
224+ rest <- getInput
225+ setInput $ (joinWithSep "\n" raw) ++ "\n\n"
226+ contents <- parseBlocks
227+ setInput rest
228+ return (NoteBlock ref contents)
185229
186230--
187231-- parsing blocks
@@ -189,9 +233,17 @@ parseMarkdown = do
189233
190234parseBlocks = manyTill block eof
191235
192−block = choice [ header, table, codeBlock, note, referenceKey, hrule, list,
193− blockQuote, htmlBlock, rawLaTeXEnvironment', para,
194− plain, nullBlock ] <?> "block"
236+block = choice [ header
237+ , table
238+ , codeBlock
239+ , hrule
240+ , list
241+ , blockQuote
242+ , htmlBlock
243+ , rawLaTeXEnvironment'
244+ , para
245+ , plain
246+ , nullBlock ] <?> "block"
195247
196248--
197249-- header blocks
@@ -261,45 +313,6 @@ codeBlock = do
261313 option "" blanklines
262314 return (CodeBlock (stripTrailingNewlines result))
263315
264−--
265−-- note block
266−--
267−
268−rawLine = try (do
269− notFollowedBy' blankline
270− notFollowedBy' noteMarker
271− contents <- many1 nonEndline
272− end <- option "" (do
273− newline
274− option "" (try indentSpaces)
275− return "\n")
276− return (contents ++ end))
277−
278−rawLines = do
279− lines <- many1 rawLine
280− return (concat lines)
281−
282−note = try (do
283− failIfStrict
284− ref <- noteMarker
285− char ':'
286− skipSpaces
287− skipEndline
288− raw <- sepBy rawLines (try (do {blankline; indentSpaces}))
289− option "" blanklines
290− -- parse the extracted text, which may contain various block elements:
291− rest <- getInput
292− setInput $ (joinWithSep "\n" raw) ++ "\n\n"
293− contents <- parseBlocks
294− setInput rest
295− state <- getState
296− let identifiers = stateNoteIdentifiers state
297− case (findIndex (== ref) identifiers) of
298− Just n -> updateState (\s -> s {stateNoteBlocks =
299− (Note (show (n+1)) contents):(stateNoteBlocks s)})
300− Nothing -> updateState id
301− return Null)
302−
303316--
304317-- block quotes
305318--
@@ -535,25 +548,6 @@ rawHtmlBlocks = try (do
535548 else combined
536549 return (RawHtml combined'))
537550
538−--
539−-- reference key
540−--
541−
542−referenceKey = try (do
543− nonindentSpaces
544− label <- reference
545− char labelSep
546− skipSpaces
547− option ' ' (char autoLinkStart)
548− src <- many (noneOf (titleOpeners ++ [autoLinkEnd] ++ endLineChars))
549− option ' ' (char autoLinkEnd)
550− tit <- option "" title
551− blanklines
552− state <- getState
553− let keysUsed = stateKeysUsed state
554− setState state { stateKeysUsed = (label:keysUsed) }
555− return $ Key label (Src (removeTrailingSpace src) tit))
556−
557551--
558552-- LaTeX
559553--
@@ -713,7 +707,7 @@ table = do
713707inline = choice [ rawLaTeXInline'
714708 , escapedChar
715709 , entity
716− , noteRef
710+ , note
717711 , inlineNote
718712 , link
719713 , referenceLink
@@ -933,7 +927,7 @@ reference = try $ do
933927 return (normalizeSpaces label)
934928
935929-- source for a link, with optional title
936−source = try (do
930+source = try $ do
937931 char srcStart
938932 option ' ' (char autoLinkStart)
939933 src <- many (noneOf ([srcEnd, autoLinkEnd] ++ titleOpeners))
@@ -941,7 +935,7 @@ source = try (do
941935 tit <- option "" title
942936 skipSpaces
943937 char srcEnd
944− return (Src (removeTrailingSpace src) tit))
938+ return (removeTrailingSpace src, tit)
945939
946940titleWith startChar endChar = try (do
947941 skipSpaces
@@ -965,30 +959,18 @@ explicitLink = try (do
965959 src <- source
966960 return (Link label src))
967961
968−referenceLink = choice [referenceLinkDouble, referenceLinkSingle]
969−
970−-- a link like [this][ref]
971−referenceLinkDouble = try (do
962+-- a link like [this][ref] or [this][] or [this]
963+referenceLink = try $ do
972964 label <- reference
973− skipSpaces
974− option ' ' newline
975− skipSpaces
976− ref <- reference
965+ ref <- option [] (try (do skipSpaces
966+ option ' ' newline
967+ skipSpaces
968+ reference))
977969 let ref' = if null ref then label else ref
978970 state <- getState
979− if ref' `elem` (stateKeysUsed state)
980− then return ()
981− else fail "no corresponding key"
982− return (Link label (Ref ref')))
983−
984−-- a link like [this]
985−referenceLinkSingle = try (do
986− label <- reference
987− state <- getState
988− if label `elem` (stateKeysUsed state)
989− then return ()
990− else fail "no corresponding key"
991− return (Link label (Ref label)))
971+ case lookupKeySrc (stateKeys state) ref' of
972+ Nothing -> fail "no corresponding key"
973+ Just target -> return (Link label target)
992974
993975autoLink = autoLinkEmail <|> autoLinkRegular
994976
@@ -999,7 +981,7 @@ autoLinkEmail = try $ do
999981 domain <- sepBy1 (many1 (noneOf "/:.@<> \t\n")) (char '.')
1000982 let src = name ++ "@" ++ (joinWithSep "." domain)
1001983 char autoLinkEnd
1002− return $ Link [Str src] (Src ("mailto:" ++ src) "")
984+ return $ Link [Str src] (("mailto:" ++ src), "")
1003985
1004986-- a link <http://like.this.com>
1005987autoLinkRegular = try $ do
@@ -1007,39 +989,28 @@ autoLinkRegular = try $ do
1007989 prot <- oneOfStrings ["http:", "ftp:", "mailto:"]
1008990 rest <- many1Till (noneOf " \t\n<>") (char autoLinkEnd)
1009991 let src = prot ++ rest
1010− return $ Link [Str src] (Src src "")
992+ return $ Link [Str src] (src, "")
1011993
1012994image = try (do
1013995 char imageStart
1014996 (Link label src) <- link
1015997 return (Image label src))
1016998
1017−noteMarker = try (do
1018− char labelStart
1019− char noteStart
1020− manyTill (noneOf " \t\n") (char labelEnd))
1021−
1022−noteRef = try (do
999+note = try $ do
10231000 failIfStrict
10241001 ref <- noteMarker
10251002 state <- getState
1026− let identifiers = (stateNoteIdentifiers state) ++ [ref]
1027− setState state {stateNoteIdentifiers = identifiers}
1028− return (NoteRef (show (length identifiers))))
1003+ let notes = stateNotes state
1004+ case lookup ref notes of
1005+ Nothing -> fail "note not found"
1006+ Just contents -> return (Note contents)
10291007
1030−inlineNote = try (do
1008+inlineNote = try $ do
10311009 failIfStrict
10321010 char noteStart
10331011 char labelStart
10341012 contents <- manyTill inline (char labelEnd)
1035− state <- getState
1036− let identifiers = stateNoteIdentifiers state
1037− let ref = show $ (length identifiers) + 1
1038− let noteBlocks = stateNoteBlocks state
1039− setState state {stateNoteIdentifiers = (identifiers ++ [ref]),
1040− stateNoteBlocks =
1041− (Note ref [Para contents]):noteBlocks}
1042− return (NoteRef ref))
1013+ return (Note [Para contents])
10431014
10441015rawLaTeXInline' = do
10451016 failIfStrict
src/Text/Pandoc/Readers/RST.hs+66−64
@@ -37,8 +37,8 @@ import Text.Pandoc.Readers.HTML ( anyHtmlBlockTag, anyHtmlInlineTag )
3737import Text.Regex ( matchRegex, mkRegex )
3838import Text.ParserCombinators.Parsec
3939import Data.Maybe ( fromMaybe )
40−import List ( findIndex )
41−import Char ( toUpper )
40+import Data.List ( findIndex, delete )
41+import Data.Char ( toUpper )
4242
4343-- | Parse reStructuredText string and return Pandoc document.
4444readRST :: ParserState -> String -> Pandoc
@@ -62,11 +62,7 @@ specialChars = "\\`|*_<>$:[-"
6262-- parsing documents
6363--
6464
65−isAnonKeyBlock block = case block of
66− (Key [Str "_"] str) -> True
67− otherwise -> False
68−
69−isNotAnonKeyBlock block = not (isAnonKeyBlock block)
65+isAnonKey (ref, src) = (ref == [Str "_"])
7066
7167isHeader1 :: Block -> Bool
7268isHeader1 (Header 1 _) = True
@@ -101,20 +97,22 @@ titleTransform blocks = (blocks, [])
10197
10298parseRST = do
10399 -- first pass: get anonymous keys
104− keyBlocks <- lookAhead $ manyTill (anonymousKey <|> (do{anyLine; return Null})) eof
105− let anonymousKeys = filter (/= Null) keyBlocks
106− -- run parser again to fill in anonymous links...
107− updateState (\st -> st { stateKeyBlocks = anonymousKeys })
108− state <- getState
100+ refs <- manyTill (referenceKey <|> (do l <- lineClump
101+ return (LineClump l))) eof
102+ let keys = map (\(KeyBlock label target) -> (label, target)) $
103+ filter isKeyBlock refs
104+ let rawlines = map (\(LineClump ln) -> ln) $ filter isLineClump refs
105+ setInput $ concat rawlines -- with keys stripped out
106+ updateState (\state -> state { stateKeys = keys })
109107 blocks <- parseBlocks
110− let blocks' = filter isNotAnonKeyBlock blocks
108+ let blocks' = filter (/= Null) blocks
109+ state <- getState
111110 let (blocks'', title) = if stateStandalone state
112111 then titleTransform blocks'
113112 else (blocks', [])
114− state' <- getState
115− let authors = stateAuthors state'
116− let date = stateDate state'
117− let title' = if (null title) then (stateTitle state') else title
113+ let authors = stateAuthors state
114+ let date = stateDate state
115+ let title' = if (null title) then (stateTitle state) else title
118116 return (Pandoc (Meta title' authors date) blocks'')
119117
120118--
@@ -124,7 +122,7 @@ parseRST = do
124122parseBlocks = manyTill block eof
125123
126124block = choice [ codeBlock, rawHtmlBlock, rawLaTeXBlock, blockQuote,
127− referenceKey, imageBlock, unknownDirective, header,
125+ imageBlock, unknownDirective, header,
128126 hrule, list, fieldList, lineBlock, para, plain,
129127 nullBlock ] <?> "block"
130128
@@ -221,7 +219,7 @@ plain = do
221219imageBlock = try (do
222220 string ".. image:: "
223221 src <- manyTill anyChar newline
224− return (Plain [Image [Str "image"] (Src src "")]))
222+ return (Plain [Image [Str "image"] (src, "")]))
225223
226224--
227225-- header blocks
@@ -492,43 +490,43 @@ unknownDirective = try (do
492490-- reference key
493491--
494492
495−referenceKey = choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
493+referenceKey = do
494+ result <- choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
495+ option "" blanklines
496+ return result
496497
497−imageKey = try (do
498+imageKey = try $ do
498499 string ".. |"
499500 ref <- manyTill inline (char '|')
500501 skipSpaces
501502 string "image::"
502503 src <- manyTill anyChar newline
503− return (Key (normalizeSpaces ref)
504− (Src (removeLeadingTrailingSpace src) "")))
504+ return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
505505
506−anonymousKey = try (do
506+anonymousKey = try $ do
507507 oneOfStrings [".. __:", "__"]
508508 skipSpaces
509509 option ' ' newline
510510 src <- manyTill anyChar newline
511511 state <- getState
512− return (Key [Str "_"] (Src (removeLeadingTrailingSpace src) "")))
512+ return $ KeyBlock [Str "_"] (removeLeadingTrailingSpace src, "")
513513
514−regularKeyQuoted = try (do
514+regularKeyQuoted = try $ do
515515 string ".. _`"
516516 ref <- manyTill inline (char '`')
517517 char ':'
518518 skipSpaces
519519 option ' ' newline
520520 src <- manyTill anyChar newline
521− return (Key (normalizeSpaces ref)
522− (Src (removeLeadingTrailingSpace src) "")))
521+ return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
523522
524−regularKey = try (do
523+regularKey = try $ do
525524 string ".. _"
526525 ref <- manyTill inline (char ':')
527526 skipSpaces
528527 option ' ' newline
529528 src <- manyTill anyChar newline
530− return (Key (normalizeSpaces ref)
531− (Src (removeLeadingTrailingSpace src) "")))
529+ return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
532530
533531 --
534532 -- inline
@@ -577,7 +575,7 @@ tabchar = do
577575 return (Str "\t")
578576
579577str = do
580− notFollowedBy' oneWordReferenceLink
578+ notFollowedBy' oneWordReference
581579 result <- many1 (noneOf (specialChars ++ "\t\n "))
582580 return (Str result)
583581
@@ -596,46 +594,44 @@ endline = try (do
596594-- links
597595--
598596
599−link = choice [explicitLink, referenceLink, autoLink,
600− oneWordReferenceLink] <?> "link"
597+link = choice [explicitLink, referenceLink, autoLink] <?> "link"
601598
602−explicitLink = try (do
599+explicitLink = try $ do
603600 char '`'
604601 notFollowedBy (char '`') -- `` is marks start of inline code
605602 label <- manyTill inline (try (do {spaces; char '<'}))
606603 src <- manyTill (noneOf ">\n ") (char '>')
607604 skipSpaces
608605 string "`_"
609− return (Link (normalizeSpaces label)
610− (Src (removeLeadingTrailingSpace src) "")))
606+ return $ Link (normalizeSpaces label) (removeLeadingTrailingSpace src, "")
611607
612−anonymousLinkEnding = try (do
613− char '_'
614− state <- getState
615− let anonKeys = stateKeyBlocks state
616− -- if there's a list of anon key refs (from previous pass), pop one off.
617− -- otherwise return an anon key ref for the next pass to take care of...
618− case anonKeys of
619− (Key [Str "_"] src):rest ->
620− do
621− setState (state { stateKeyBlocks = rest })
622− return src
623− otherwise -> return (Ref [Str "_"]))
624−
625−referenceLink = try (do
608+reference = try $ do
626609 char '`'
627610 notFollowedBy (char '`')
628− label <- manyTill inline (char '`')
611+ label <- many1Till inline (char '`')
629612 char '_'
630− src <- option (Ref []) anonymousLinkEnding
631− return (Link (normalizeSpaces label) src))
613+ return label
632614
633−oneWordReferenceLink = try (do
634− label <- many1 alphaNum
615+oneWordReference = do
616+ raw <- many1 alphaNum
635617 char '_'
636− src <- option (Ref []) anonymousLinkEnding
637618 notFollowedBy alphaNum -- because this_is_not a link
638− return (Link [Str label] src))
619+ return [Str raw]
620+
621+referenceLink = try $ do
622+ label <- reference <|> oneWordReference
623+ key <- option label (do{char '_'; return [Str "_"]}) -- anonymous link
624+ state <- getState
625+ let keyTable = stateKeys state
626+ src <- case lookupKeySrc keyTable key of
627+ Nothing -> fail "no corresponding key"
628+ Just target -> return target
629+ -- if anonymous link, remove first anon key so it won't be used again
630+ let keyTable' = if (key == [Str "_"]) -- anonymous link?
631+ then delete ([Str "_"], src) keyTable -- remove first anon key
632+ else keyTable
633+ setState $ state { stateKeys = keyTable' }
634+ return $ Link (normalizeSpaces label) src
639635
640636uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://",
641637 "mailto:", "news:", "telnet:" ]
@@ -645,9 +641,9 @@ uri = try (do
645641 identifier <- many1 (noneOf " \t\n")
646642 return (scheme ++ identifier))
647643
648−autoURI = try (do
644+autoURI = try $ do
649645 src <- uri
650− return (Link [Str src] (Src src "")))
646+ return $ Link [Str src] (src, "")
651647
652648emailChar = alphaNum <|> oneOf "-+_."
653649
@@ -666,14 +662,20 @@ domain = try (do
666662 dom <- many1 (try (do{ char '.'; many1 domainChar }))
667663 return (joinWithSep "." (first:dom)))
668664
669−autoEmail = try (do
665+autoEmail = try $ do
670666 src <- emailAddress
671− return (Link [Str src] (Src ("mailto:" ++ src) "")))
667+ return $ Link [Str src] ("mailto:" ++ src, "")
672668
673669autoLink = autoURI <|> autoEmail
674670
675671-- For now, we assume that all substitution references are for images.
676−image = try (do
672+image = try $ do
677673 char '|'
678674 ref <- manyTill inline (char '|')
679− return (Image (normalizeSpaces ref) (Ref ref)))
675+ state <- getState
676+ let keyTable = stateKeys state
677+ src <- case lookupKeySrc keyTable ref of
678+ Nothing -> fail "no corresponding key"
679+ Just target -> return target
680+ return (Image (normalizeSpaces ref) src)
681+
src/Text/Pandoc/Shared.hs+39−188
@@ -45,6 +45,10 @@ module Text.Pandoc.Shared (
4545 -- * Parsing
4646 readWith,
4747 testStringWith,
48+ Reference (..),
49+ isNoteBlock,
50+ isKeyBlock,
51+ isLineClump,
4852 HeaderType (..),
4953 ParserContext (..),
5054 QuoteContext (..),
@@ -53,27 +57,19 @@ module Text.Pandoc.Shared (
5357 -- * Native format prettyprinting
5458 prettyPandoc,
5559 -- * Pandoc block list processing
56− isNoteBlock,
5760 normalizeSpaces,
5861 compactify,
59− generateReference,
62+ -- * Writer options
6063 WriterOptions (..),
6164 defaultWriterOptions,
65+ -- * Reference key lookup functions
6266 KeyTable,
63− keyTable,
6467 lookupKeySrc,
6568 refsMatch,
66− replaceReferenceLinks,
67− replaceRefLinksBlockList,
68− -- * SGML
69− inTags,
70− selfClosingTag,
71− inTagsSimple,
72− inTagsIndented
7369 ) where
7470import Text.Pandoc.Definition
7571import Text.ParserCombinators.Parsec as Parsec
76−import Text.Pandoc.Entities ( decodeEntities, escapeSGMLString )
72+import Text.Pandoc.Entities ( decodeEntities, escapeStringForXML )
7773import Text.PrettyPrint.HughesPJ as PP ( text, char, (<>),
7874 ($$), nest, Doc, isEmpty )
7975import Data.Char ( toLower, ord )
@@ -113,16 +109,37 @@ data QuoteContext
113109 | NoQuote -- ^ Used when we're not parsing inside quotes
114110 deriving (Eq, Show)
115111
112+type KeyTable = [([Inline], Target)]
113+
114+type NoteTable = [(String, [Block])]
115+
116+-- | References from preliminary parsing
117+data Reference
118+ = KeyBlock [Inline] Target -- ^ Key for reference-style link (label URL title)
119+ | NoteBlock String [Block] -- ^ Footnote reference and contents
120+ | LineClump String -- ^ Raw clump of lines with blanks at end
121+ deriving (Eq, Read, Show)
122+
123+-- | Auxiliary functions used in preliminary parsing
124+isNoteBlock :: Reference -> Bool
125+isNoteBlock (NoteBlock _ _) = True
126+isNoteBlock _ = False
127+
128+isKeyBlock :: Reference -> Bool
129+isKeyBlock (KeyBlock _ _) = True
130+isKeyBlock _ = False
131+
132+isLineClump :: Reference -> Bool
133+isLineClump (LineClump _) = True
134+isLineClump _ = False
135+
116136data ParserState = ParserState
117137 { stateParseRaw :: Bool, -- ^ Parse untranslatable HTML
118138 -- and LaTeX?
119139 stateParserContext :: ParserContext, -- ^ What are we parsing?
120140 stateQuoteContext :: QuoteContext, -- ^ Inside quoted environment?
121− stateKeyBlocks :: [Block], -- ^ List of reference key blocks
122− stateKeysUsed :: [[Inline]], -- ^ List of references used
123− stateNoteBlocks :: [Block], -- ^ List of note blocks
124− stateNoteIdentifiers :: [String], -- ^ List of footnote identifiers
125− -- in the order encountered
141+ stateKeys :: KeyTable, -- ^ List of reference keys
142+ stateNotes :: NoteTable, -- ^ List of notes
126143 stateTabStop :: Int, -- ^ Tab stop
127144 stateStandalone :: Bool, -- ^ If @True@, parse
128145 -- bibliographic info
@@ -133,7 +150,6 @@ data ParserState = ParserState
133150 stateSmart :: Bool, -- ^ Use smart typography
134151 stateColumns :: Int, -- ^ Number of columns in
135152 -- terminal (used for tables)
136− stateInlineLinks :: Bool, -- ^ Parse html links as inline
137153 stateHeaderTable :: [HeaderType] -- ^ List of header types used,
138154 -- in what order (rst only)
139155 }
@@ -144,10 +160,8 @@ defaultParserState =
144160 ParserState { stateParseRaw = False,
145161 stateParserContext = NullState,
146162 stateQuoteContext = NoQuote,
147− stateKeyBlocks = [],
148− stateKeysUsed = [],
149− stateNoteBlocks = [],
150− stateNoteIdentifiers = [],
163+ stateKeys = [],
164+ stateNotes = [],
151165 stateTabStop = 4,
152166 stateStandalone = False,
153167 stateTitle = [],
@@ -156,7 +170,6 @@ defaultParserState =
156170 stateStrict = False,
157171 stateSmart = False,
158172 stateColumns = 80,
159− stateInlineLinks = False,
160173 stateHeaderTable = [] }
161174
162175-- | Indent string as a block.
@@ -182,8 +195,6 @@ prettyBlockList indent blocks = indentBy indent (-2) $ "[ " ++
182195prettyBlock :: Block -> String
183196prettyBlock (BlockQuote blocks) = "BlockQuote\n " ++
184197 (prettyBlockList 2 blocks)
185−prettyBlock (Note ref blocks) = "Note " ++ (show ref) ++ "\n " ++
186− (prettyBlockList 2 blocks)
187198prettyBlock (OrderedList blockLists) =
188199 "OrderedList\n" ++ indentBy 2 0 ("[ " ++ (joinWithSep ", "
189200 (map (\blocks -> prettyBlockList 2 blocks) blockLists))) ++ " ]"
@@ -236,11 +247,6 @@ endsWith :: Char -> [Char] -> Bool
236247endsWith char [] = False
237248endsWith char str = (char == last str)
238249
239−-- | Returns @True@ if block is a @Note@ block
240−isNoteBlock :: Block -> Bool
241−isNoteBlock (Note ref blocks) = True
242−isNoteBlock _ = False
243−
244250-- | Joins a list of lists, separated by another list.
245251joinWithSep :: [a] -- ^ List to use as separator
246252 -> [[a]] -- ^ Lists to join
@@ -351,9 +357,9 @@ data WriterOptions = WriterOptions
351357 , writerIncremental :: Bool -- ^ Incremental S5 lists
352358 , writerNumberSections :: Bool -- ^ Number sections in LaTeX
353359 , writerStrictMarkdown :: Bool -- ^ Use strict markdown syntax
360+ , writerReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
354361 , writerTabStop :: Int -- ^ Tabstop for conversion between
355362 -- spaces and tabs
356− , writerNotes :: [Block] -- ^ List of note blocks
357363 } deriving Show
358364
359365-- | Default writer options.
@@ -362,79 +368,18 @@ defaultWriterOptions =
362368 writerHeader = "",
363369 writerTitlePrefix = "",
364370 writerTabStop = 4,
365− writerNotes = [],
366371 writerS5 = False,
367372 writerIncremental = False,
368373 writerNumberSections = False,
369374 writerIncludeBefore = "",
370375 writerIncludeAfter = "",
371− writerStrictMarkdown = False }
372−
373−--
374−-- Functions for constructing lists of reference keys
375−--
376−
377−-- | Returns @Just@ numerical key reference if there's already a key
378−-- for the specified target in the list of blocks, otherwise @Nothing@.
379−keyFoundIn :: [Block] -- ^ List of key blocks to search
380− -> Target -- ^ Target to search for
381− -> Maybe String
382−keyFoundIn [] src = Nothing
383−keyFoundIn ((Key [Str num] src1):rest) src = if (src1 == src)
384− then Just num
385− else keyFoundIn rest src
386−keyFoundIn (_:rest) src = keyFoundIn rest src
387−
388−-- | Return next unique numerical key, given keyList
389−nextUniqueKey :: [[Inline]] -> String
390−nextUniqueKey keys =
391− let nums = [1..10000]
392− notAKey n = not (any (== [Str (show n)]) keys) in
393− case (find notAKey nums) of
394− Just x -> show x
395− Nothing -> error "Could not find unique key for reference link"
396−
397−-- | Generate a reference for a URL (either an existing reference, if
398−-- there is one, or a new one, if there isn't) and update parser state.
399−generateReference :: String -- ^ URL
400− -> String -- ^ Title
401− -> GenParser tok ParserState Target
402−generateReference url title = do
403− let src = Src (decodeEntities url) (decodeEntities title)
404− state <- getState
405− let keyBlocks = stateKeyBlocks state
406− let keysUsed = stateKeysUsed state
407− case (keyFoundIn keyBlocks src) of
408− Just num -> return (Ref [Str num])
409− Nothing -> do
410− let nextNum = nextUniqueKey keysUsed
411− updateState (\st -> st { stateKeyBlocks =
412− (Key [Str nextNum] src):keyBlocks,
413− stateKeysUsed =
414− [Str nextNum]:keysUsed })
415− return (Ref [Str nextNum])
376+ writerStrictMarkdown = False,
377+ writerReferenceLinks = False }
416378
417379--
418−-- code to replace reference links with real links and remove unneeded key blocks
380+-- code to lookup reference keys in key table
419381--
420382
421−type KeyTable = [([Inline], Target)]
422−
423−-- | Returns @True@ if block is a Key block
424−isRefBlock :: Block -> Bool
425−isRefBlock (Key _ _) = True
426−isRefBlock _ = False
427−
428−-- | Returns a pair of a list of pairs of keys and associated sources, and a new
429−-- list of blocks with the included key blocks deleted.
430−keyTable :: [Block] -> (KeyTable, [Block])
431−keyTable [] = ([],[])
432−keyTable ((Key ref target):lst) = (((ref, target):table), rest)
433− where (table, rest) = keyTable lst
434−keyTable (Null:lst) = keyTable lst -- get rid of Nulls
435−keyTable (other:lst) = (table, (other:rest))
436− where (table, rest) = keyTable lst
437−
438383-- | Look up key in key table and return target object.
439384lookupKeySrc :: KeyTable -- ^ Key table
440385 -> [Inline] -- ^ Key
@@ -455,8 +400,6 @@ refsMatch ((TeX x):restx) ((TeX y):resty) =
455400 ((map toLower x) == (map toLower y)) && refsMatch restx resty
456401refsMatch ((HtmlInline x):restx) ((HtmlInline y):resty) =
457402 ((map toLower x) == (map toLower y)) && refsMatch restx resty
458−refsMatch ((NoteRef x):restx) ((NoteRef y):resty) =
459− ((map toLower x) == (map toLower y)) && refsMatch restx resty
460403refsMatch ((Emph x):restx) ((Emph y):resty) =
461404 refsMatch x y && refsMatch restx resty
462405refsMatch ((Strong x):restx) ((Strong y):resty) =
@@ -467,95 +410,3 @@ refsMatch (x:restx) (y:resty) = (x == y) && refsMatch restx resty
467410refsMatch [] x = null x
468411refsMatch x [] = null x
469412
470−-- | Replace reference links with explicit links in list of blocks,
471−-- removing key blocks.
472−replaceReferenceLinks :: [Block] -> [Block]
473−replaceReferenceLinks blocks =
474− let (keytable, purged) = keyTable blocks in
475− replaceRefLinksBlockList keytable purged
476−
477−-- | Use key table to replace reference links with explicit links in a list
478−-- of blocks
479−replaceRefLinksBlockList :: KeyTable -> [Block] -> [Block]
480−replaceRefLinksBlockList keytable lst =
481− map (replaceRefLinksBlock keytable) lst
482−
483−-- | Use key table to replace reference links with explicit links in a block
484−replaceRefLinksBlock :: KeyTable -> Block -> Block
485−replaceRefLinksBlock keytable (Plain lst) =
486− Plain (map (replaceRefLinksInline keytable) lst)
487−replaceRefLinksBlock keytable (Para lst) =
488− Para (map (replaceRefLinksInline keytable) lst)
489−replaceRefLinksBlock keytable (Header lvl lst) =
490− Header lvl (map (replaceRefLinksInline keytable) lst)
491−replaceRefLinksBlock keytable (BlockQuote lst) =
492− BlockQuote (map (replaceRefLinksBlock keytable) lst)
493−replaceRefLinksBlock keytable (Note ref lst) =
494− Note ref (map (replaceRefLinksBlock keytable) lst)
495−replaceRefLinksBlock keytable (OrderedList lst) =
496− OrderedList (map (replaceRefLinksBlockList keytable) lst)
497−replaceRefLinksBlock keytable (BulletList lst) =
498− BulletList (map (replaceRefLinksBlockList keytable) lst)
499−replaceRefLinksBlock keytable (DefinitionList lst) =
500− DefinitionList (map (\(term, def) ->
501− (map (replaceRefLinksInline keytable) term,
502− replaceRefLinksBlockList keytable def)) lst)
503−replaceRefLinksBlock keytable (Table caption alignment widths headers rows) =
504− Table (map (replaceRefLinksInline keytable) caption) alignment widths
505− (map (replaceRefLinksBlockList keytable) headers)
506− (map (map (replaceRefLinksBlockList keytable)) rows)
507−replaceRefLinksBlock keytable other = other
508−
509−-- | Use key table to replace reference links with explicit links in an
510−-- inline element.
511−replaceRefLinksInline :: KeyTable -> Inline -> Inline
512−replaceRefLinksInline keytable (Link text (Ref ref)) = (Link newText newRef)
513− where newRef = case lookupKeySrc keytable
514− (if (null ref) then text else ref) of
515− Nothing -> (Ref ref)
516− Just src -> src
517− newText = map (replaceRefLinksInline keytable) text
518−replaceRefLinksInline keytable (Image text (Ref ref)) = (Image newText newRef)
519− where newRef = case lookupKeySrc keytable
520− (if (null ref) then text else ref) of
521− Nothing -> (Ref ref)
522− Just src -> src
523− newText = map (replaceRefLinksInline keytable) text
524−replaceRefLinksInline keytable (Emph lst) =
525− Emph (map (replaceRefLinksInline keytable) lst)
526−replaceRefLinksInline keytable (Strong lst) =
527− Strong (map (replaceRefLinksInline keytable) lst)
528−replaceRefLinksInline keytable (Quoted t lst) =
529− Quoted t (map (replaceRefLinksInline keytable) lst)
530−replaceRefLinksInline keytable other = other
531−
532−-- | Return a text object with a string of formatted SGML attributes.
533−attributeList :: [(String, String)] -> Doc
534−attributeList = text . concatMap
535− (\(a, b) -> " " ++ escapeSGMLString a ++ "=\"" ++
536− escapeSGMLString b ++ "\"")
537−
538−-- | Put the supplied contents between start and end tags of tagType,
539−-- with specified attributes and (if specified) indentation.
540−inTags:: Bool -> String -> [(String, String)] -> Doc -> Doc
541−inTags isIndented tagType attribs contents =
542− let openTag = PP.char '<' <> text tagType <> attributeList attribs <>
543− PP.char '>'
544− closeTag = text "</" <> text tagType <> PP.char '>' in
545− if isIndented
546− then openTag $$ nest 2 contents $$ closeTag
547− else openTag <> contents <> closeTag
548−
549−-- | Return a self-closing tag of tagType with specified attributes
550−selfClosingTag :: String -> [(String, String)] -> Doc
551−selfClosingTag tagType attribs =
552− PP.char '<' <> text tagType <> attributeList attribs <> text " />"
553−
554−-- | Put the supplied contents between start and end tags of tagType.
555−inTagsSimple :: String -> Doc -> Doc
556−inTagsSimple tagType = inTags False tagType []
557−
558−-- | Put the supplied contents in indented block btw start and end tags.
559−inTagsIndented :: String -> Doc -> Doc
560−inTagsIndented tagType = inTags True tagType []
561−
src/Text/Pandoc/Writers/Docbook.hs+60−35
@@ -27,16 +27,53 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2727
2828Conversion of 'Pandoc' documents to Docbook XML.
2929-}
30−module Text.Pandoc.Writers.Docbook (
31− writeDocbook
32− ) where
30+module Text.Pandoc.Writers.Docbook ( writeDocbook) where
3331import Text.Pandoc.Definition
3432import Text.Pandoc.Shared
35−import Text.Pandoc.Entities ( escapeSGMLString )
33+import Text.Pandoc.Entities ( escapeStringForXML )
3634import Data.Char ( toLower, ord )
3735import Data.List ( isPrefixOf, partition, drop )
3836import Text.PrettyPrint.HughesPJ hiding ( Str )
3937
38+
39+--
40+-- code to format XML
41+--
42+
43+-- | Return a text object with a string of formatted XML attributes.
44+attributeList :: [(String, String)] -> Doc
45+attributeList = text . concatMap
46+ (\(a, b) -> " " ++ escapeStringForXML a ++ "=\"" ++
47+ escapeStringForXML b ++ "\"")
48+
49+-- | Put the supplied contents between start and end tags of tagType,
50+-- with specified attributes and (if specified) indentation.
51+inTags:: Bool -> String -> [(String, String)] -> Doc -> Doc
52+inTags isIndented tagType attribs contents =
53+ let openTag = char '<' <> text tagType <> attributeList attribs <>
54+ char '>'
55+ closeTag = text "</" <> text tagType <> char '>' in
56+ if isIndented
57+ then openTag $$ nest 2 contents $$ closeTag
58+ else openTag <> contents <> closeTag
59+
60+-- | Return a self-closing tag of tagType with specified attributes
61+selfClosingTag :: String -> [(String, String)] -> Doc
62+selfClosingTag tagType attribs =
63+ char '<' <> text tagType <> attributeList attribs <> text " />"
64+
65+-- | Put the supplied contents between start and end tags of tagType.
66+inTagsSimple :: String -> Doc -> Doc
67+inTagsSimple tagType = inTags False tagType []
68+
69+-- | Put the supplied contents in indented block btw start and end tags.
70+inTagsIndented :: String -> Doc -> Doc
71+inTagsIndented tagType = inTags True tagType []
72+
73+--
74+-- Docbook writer
75+--
76+
4077-- | Data structure for defining hierarchical Pandoc documents
4178data Element = Blk Block
4279 | Sec [Inline] [Element] deriving (Eq, Read, Show)
@@ -64,8 +101,8 @@ authorToDocbook name = inTagsIndented "author" $
64101 then -- last name first
65102 let (lastname, rest) = break (==',') name
66103 firstname = removeLeadingSpace rest in
67− inTagsSimple "firstname" (text $ escapeSGMLString firstname) <>
68− inTagsSimple "surname" (text $ escapeSGMLString lastname)
104+ inTagsSimple "firstname" (text $ escapeStringForXML firstname) <>
105+ inTagsSimple "surname" (text $ escapeStringForXML lastname)
69106 else -- last name last
70107 let namewords = words name
71108 lengthname = length namewords
@@ -73,8 +110,8 @@ authorToDocbook name = inTagsIndented "author" $
73110 0 -> ("","")
74111 1 -> ("", name)
75112 n -> (joinWithSep " " (take (n-1) namewords), last namewords) in
76− inTagsSimple "firstname" (text $ escapeSGMLString firstname) $$
77− inTagsSimple "surname" (text $ escapeSGMLString lastname)
113+ inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
114+ inTagsSimple "surname" (text $ escapeStringForXML lastname)
78115
79116-- | Convert Pandoc document to string in Docbook format.
80117writeDocbook :: WriterOptions -> Pandoc -> String
@@ -86,18 +123,15 @@ writeDocbook opts (Pandoc (Meta title authors date) blocks) =
86123 then inTagsIndented "articleinfo" $
87124 (inTagsSimple "title" (wrap opts title)) $$
88125 (vcat (map authorToDocbook authors)) $$
89− (inTagsSimple "date" (text $ escapeSGMLString date))
126+ (inTagsSimple "date" (text $ escapeStringForXML date))
90127 else empty
91− blocks' = replaceReferenceLinks blocks
92− (noteBlocks, blocks'') = partition isNoteBlock blocks'
93− opts' = opts {writerNotes = noteBlocks}
94− elements = hierarchicalize blocks''
95− before = writerIncludeBefore opts'
96− after = writerIncludeAfter opts'
128+ elements = hierarchicalize blocks
129+ before = writerIncludeBefore opts
130+ after = writerIncludeAfter opts
97131 body = (if null before then empty else text before) $$
98− vcat (map (elementToDocbook opts') elements) $$
132+ vcat (map (elementToDocbook opts) elements) $$
99133 (if null after then empty else text after)
100− body' = if writerStandalone opts'
134+ body' = if writerStandalone opts
101135 then inTagsIndented "article" (meta $$ body)
102136 else body in
103137 render $ head $$ body' $$ text ""
@@ -140,15 +174,13 @@ blockToDocbook opts (Para lst) =
140174blockToDocbook opts (BlockQuote blocks) =
141175 inTagsIndented "blockquote" (blocksToDocbook opts blocks)
142176blockToDocbook opts (CodeBlock str) =
143− text "<screen>\n" <> text (escapeSGMLString str) <> text "\n</screen>"
177+ text "<screen>\n" <> text (escapeStringForXML str) <> text "\n</screen>"
144178blockToDocbook opts (BulletList lst) =
145179 inTagsIndented "itemizedlist" $ listItemsToDocbook opts lst
146180blockToDocbook opts (OrderedList lst) =
147181 inTagsIndented "orderedlist" $ listItemsToDocbook opts lst
148182blockToDocbook opts (RawHtml str) = text str -- raw XML block
149183blockToDocbook opts HorizontalRule = empty -- not semantic
150−blockToDocbook opts (Note _ _) = empty -- shouldn't occur
151−blockToDocbook opts (Key _ _) = empty -- shouldn't occur
152184blockToDocbook opts (Table caption aligns widths headers rows) =
153185 let alignStrings = map alignmentToString aligns
154186 captionDoc = if null caption
@@ -197,7 +229,7 @@ inlinesToDocbook opts lst = hcat (map (inlineToDocbook opts) lst)
197229
198230-- | Convert an inline element to Docbook.
199231inlineToDocbook :: WriterOptions -> Inline -> Doc
200−inlineToDocbook opts (Str str) = text $ escapeSGMLString str
232+inlineToDocbook opts (Str str) = text $ escapeStringForXML str
201233inlineToDocbook opts (Emph lst) =
202234 inTagsSimple "emphasis" (inlinesToDocbook opts lst)
203235inlineToDocbook opts (Strong lst) =
@@ -210,31 +242,24 @@ inlineToDocbook opts Ellipses = text "&#8230;"
210242inlineToDocbook opts EmDash = text "&#8212;"
211243inlineToDocbook opts EnDash = text "&#8211;"
212244inlineToDocbook opts (Code str) =
213− inTagsSimple "literal" $ text (escapeSGMLString str)
245+ inTagsSimple "literal" $ text (escapeStringForXML str)
214246inlineToDocbook opts (TeX str) = inlineToDocbook opts (Code str)
215247inlineToDocbook opts (HtmlInline str) = empty
216248inlineToDocbook opts LineBreak =
217249 text $ "<literallayout></literallayout>"
218250inlineToDocbook opts Space = char ' '
219−inlineToDocbook opts (Link txt (Src src tit)) =
251+inlineToDocbook opts (Link txt (src, tit)) =
220252 if isPrefixOf "mailto:" src
221− then inTagsSimple "email" $ text (escapeSGMLString $ drop 7 src)
253+ then inTagsSimple "email" $ text (escapeStringForXML $ drop 7 src)
222254 else inTags False "ulink" [("url", src)] $ inlinesToDocbook opts txt
223−inlineToDocbook opts (Link text (Ref ref)) = empty -- shouldn't occur
224−inlineToDocbook opts (Image alt (Src src tit)) =
255+inlineToDocbook opts (Image alt (src, tit)) =
225256 let titleDoc = if null tit
226257 then empty
227258 else inTagsIndented "objectinfo" $
228259 inTagsIndented "title"
229− (text $ escapeSGMLString tit) in
260+ (text $ escapeStringForXML tit) in
230261 inTagsIndented "inlinemediaobject" $
231262 inTagsIndented "imageobject" $
232263 titleDoc $$ selfClosingTag "imagedata" [("fileref", src)]
233−inlineToDocbook opts (Image alternate (Ref ref)) = empty --shouldn't occur
234−inlineToDocbook opts (NoteRef ref) =
235− let notes = writerNotes opts
236− hits = filter (\(Note r _) -> r == ref) notes in
237− if null hits
238− then empty
239− else let (Note _ contents) = head hits in
240− inTagsIndented "footnote" $ blocksToDocbook opts contents
264+inlineToDocbook opts (Note contents) =
265+ inTagsIndented "footnote" $ blocksToDocbook opts contents
src/Text/Pandoc/Writers/HTML.hs+152−137
@@ -35,8 +35,11 @@ import Text.Regex ( mkRegex, matchRegex )
3535import Numeric ( showHex )
3636import Data.Char ( ord, toLower )
3737import Data.List ( isPrefixOf, partition )
38+import Control.Monad.State
3839import Text.XHtml.Strict
3940
41+type Notes = [Html]
42+
4043-- | Convert Pandoc document to Html string.
4144writeHtmlString :: WriterOptions -> Pandoc -> String
4245writeHtmlString opts =
@@ -48,13 +51,10 @@ writeHtmlString opts =
4851writeHtml :: WriterOptions -> Pandoc -> Html
4952writeHtml opts (Pandoc (Meta tit authors date) blocks) =
5053 let titlePrefix = writerTitlePrefix opts
51− topTitle = inlineListToHtml opts tit
52− topTitle' = if not (null titlePrefix)
53− then stringToHtml titlePrefix +++
54− if not (null tit)
55− then '-' +++ topTitle
56− else noHtml
57− else topTitle
54+ topTitle = evalState (inlineListToHtml opts tit) []
55+ topTitle' = if null titlePrefix
56+ then topTitle
57+ else titlePrefix +++ " - " +++ topTitle
5858 head = header $ thetitle topTitle' +++
5959 meta ! [httpequiv "Content-Type",
6060 content "text/html; charset=UTF-8"] +++
@@ -69,31 +69,30 @@ writeHtml opts (Pandoc (Meta tit authors date) blocks) =
6969 (not (writerS5 opts))
7070 then h1 ! [theclass "title"] $ topTitle
7171 else noHtml
72− blocks' = replaceReferenceLinks blocks
73− (noteBlocks, blocks'') = partition isNoteBlock blocks'
72+ (blocks', revnotes) = runState (blockListToHtml opts blocks) []
73+ notes = reverse revnotes
7474 before = primHtml $ writerIncludeBefore opts
7575 after = primHtml $ writerIncludeAfter opts
76− thebody = before +++ titleHeader +++
77− toHtmlFromList (map (blockToHtml opts) blocks'') +++
78− footnoteSection opts noteBlocks +++ after
76+ thebody = before +++ titleHeader +++ blocks' +++
77+ footnoteSection opts notes +++ after
7978 in if writerStandalone opts
8079 then head +++ (body thebody)
8180 else thebody
8281
8382-- | Convert list of Note blocks to a footnote <div>.
8483-- Assumes notes are sorted.
85−footnoteSection :: WriterOptions -> [Block] -> Html
84+footnoteSection :: WriterOptions -> Notes -> Html
8685footnoteSection opts notes =
8786 if null notes
88− then noHtml
89− else thediv ! [theclass "footnotes"] $
90− hr +++ (olist $ toHtmlFromList $ map (blockToHtml opts) notes)
87+ then noHtml
88+ else thediv ! [theclass "footnotes"] $
89+ hr +++ (olist << notes)
9190
9291-- | Obfuscate a "mailto:" link using Javascript.
93−obfuscateLink :: WriterOptions -> [Inline] -> String -> Html
94−obfuscateLink opts txt src =
92+obfuscateLink :: WriterOptions -> Html -> String -> Html
93+obfuscateLink opts text src =
9594 let emailRegex = mkRegex "mailto:*([^@]*)@(.*)"
96− text' = show $ inlineListToHtml opts txt
95+ text' = show $ text
9796 src' = map toLower src in
9897 case (matchRegex emailRegex src') of
9998 (Just [name, domain]) ->
@@ -117,7 +116,7 @@ obfuscateLink opts txt src =
117116 "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\">'+" ++
118117 linkText ++ "+'<\\/'+'a'+'>');\n// -->\n")) +++
119118 noscript (primHtml $ obfuscateString altText)
120− _ -> anchor ! [href src] $ inlineListToHtml opts txt -- malformed email
119+ _ -> anchor ! [href src] $ text -- malformed email
121120
122121-- | Obfuscate character as entity.
123122obfuscateChar :: Char -> String
@@ -131,137 +130,153 @@ obfuscateString :: String -> String
131130obfuscateString = (concatMap obfuscateChar) . decodeEntities
132131
133132-- | Convert Pandoc block element to HTML.
134−blockToHtml :: WriterOptions -> Block -> Html
135−blockToHtml opts Null = noHtml
136−blockToHtml opts (Plain lst) = inlineListToHtml opts lst
137−blockToHtml opts (Para lst) = paragraph $ inlineListToHtml opts lst
138−blockToHtml opts (BlockQuote blocks) =
139− if (writerS5 opts)
140− then -- in S5, treat list in blockquote specially
141− -- if default is incremental, make it nonincremental;
142− -- otherwise incremental
143− let inc = not (writerIncremental opts) in
144− case blocks of
145− [BulletList lst] -> blockToHtml (opts {writerIncremental =
146− inc}) (BulletList lst)
147− [OrderedList lst] -> blockToHtml (opts {writerIncremental =
148− inc}) (OrderedList lst)
149− otherwise -> blockquote $ toHtmlFromList $
150− map (blockToHtml opts) blocks
151− else blockquote $ toHtmlFromList $ map (blockToHtml opts) blocks
152−blockToHtml opts (Note ref lst) =
153− let contents = toHtmlFromList $ map (blockToHtml opts) lst
154− backlink = anchor ! [href ("#fnref" ++ ref), theclass "footnoteBacklink",
155− title ("Jump back to footnote " ++ ref)] $
156− (primHtmlChar "#8617") in
157− li ! [identifier ("fn" ++ ref)] $ contents +++ backlink
158−blockToHtml opts (Key _ _) = noHtml
159−blockToHtml opts (CodeBlock str) =
160− pre $ thecode << (str ++ "\n") -- the final \n for consistency with Markdown.pl
161−blockToHtml opts (RawHtml str) = primHtml str
162−blockToHtml opts (BulletList lst) =
163− let attribs = if writerIncremental opts
164− then [theclass "incremental"]
165− else [] in
166− unordList ! attribs $ map (blockListToHtml opts) lst
167−blockToHtml opts (OrderedList lst) =
168− let attribs = if writerIncremental opts
169− then [theclass "incremental"]
170− else [] in
171− ordList ! attribs $ map (blockListToHtml opts) lst
172−blockToHtml opts (DefinitionList lst) =
173− let attribs = if writerIncremental opts
174− then [theclass "incremental"]
175− else [] in
176− defList ! attribs $ map (\(term, def) -> (inlineListToHtml opts term,
177− blockListToHtml opts def)) lst
178−blockToHtml opts HorizontalRule = hr
179−blockToHtml opts (Header level lst) =
180− let contents = inlineListToHtml opts lst in
181− case level of
182− 1 -> h1 contents
183− 2 -> h2 contents
184− 3 -> h3 contents
185− 4 -> h4 contents
186− 5 -> h5 contents
187− 6 -> h6 contents
188− _ -> paragraph contents
189−blockToHtml opts (Table capt aligns widths headers rows) =
190− let alignStrings = map alignmentToString aligns
191− captionDoc = if null capt
192− then noHtml
193− else caption $ inlineListToHtml opts capt in
194− table $ captionDoc +++
195− (colHeadsToHtml opts alignStrings widths headers) +++
196− (toHtmlFromList $ map (tableRowToHtml opts alignStrings) rows)
133+blockToHtml :: WriterOptions -> Block -> State Notes Html
134+blockToHtml opts block =
135+ case block of
136+ (Null) -> return $ noHtml
137+ (Plain lst) -> inlineListToHtml opts lst
138+ (Para lst) -> inlineListToHtml opts lst >>= (return . paragraph)
139+ (RawHtml str) -> return $ primHtml str
140+ (HorizontalRule) -> return $ hr
141+ (CodeBlock str) -> return $ pre $ thecode << (str ++ "\n")
142+ -- the final \n for consistency with Markdown.pl
143+ (BlockQuote blocks) -> -- in S5, treat list in blockquote specially
144+ -- if default is incremental, make it nonincremental;
145+ -- otherwise incremental
146+ if writerS5 opts
147+ then let inc = not (writerIncremental opts) in
148+ case blocks of
149+ [BulletList lst] -> blockToHtml (opts {writerIncremental = inc})
150+ (BulletList lst)
151+ [OrderedList lst] -> blockToHtml (opts {writerIncremental = inc})
152+ (OrderedList lst)
153+ otherwise -> blockListToHtml opts blocks >>=
154+ (return . blockquote)
155+ else blockListToHtml opts blocks >>= (return . blockquote)
156+ (Header level lst) -> do contents <- inlineListToHtml opts lst
157+ return $ case level of
158+ 1 -> h1 contents
159+ 2 -> h2 contents
160+ 3 -> h3 contents
161+ 4 -> h4 contents
162+ 5 -> h5 contents
163+ 6 -> h6 contents
164+ _ -> paragraph contents
165+ (BulletList lst) -> do contents <- mapM (blockListToHtml opts) lst
166+ let attribs = if writerIncremental opts
167+ then [theclass "incremental"]
168+ else []
169+ return $ unordList ! attribs $ contents
170+ (OrderedList lst) -> do contents <- mapM (blockListToHtml opts) lst
171+ let attribs = if writerIncremental opts
172+ then [theclass "incremental"]
173+ else []
174+ return $ ordList ! attribs $ contents
175+ (DefinitionList lst) -> do contents <- mapM (\(term, def) ->
176+ do term' <- inlineListToHtml opts term
177+ def' <- blockListToHtml opts def
178+ return $ (term', def'))
179+ lst
180+ let attribs = if writerIncremental opts
181+ then [theclass "incremental"]
182+ else []
183+ return $ defList ! attribs $ contents
184+ (Table capt aligns widths headers rows) ->
185+ do let alignStrings = map alignmentToString aligns
186+ captionDoc <- if null capt
187+ then return noHtml
188+ else inlineListToHtml opts capt >>=
189+ (return . caption)
190+ colHeads <- colHeadsToHtml opts alignStrings
191+ widths headers
192+ rows' <- mapM (tableRowToHtml opts alignStrings) rows
193+ return $ table $ captionDoc +++ colHeads +++ rows'
197194
198195colHeadsToHtml opts alignStrings widths headers =
199− let heads = zipWith3
200− (\align width item -> tableItemToHtml opts th align width item)
201− alignStrings widths headers in
202− tr $ toHtmlFromList heads
196+ do heads <- sequence $ zipWith3
197+ (\align width item -> tableItemToHtml opts th align width item)
198+ alignStrings widths headers
199+ return $ tr $ toHtmlFromList heads
203200
204201alignmentToString alignment = case alignment of
205202 AlignLeft -> "left"
206203 AlignRight -> "right"
207204 AlignCenter -> "center"
208205 AlignDefault -> "left"
206+
209207tableRowToHtml opts aligns cols =
210− tr $ toHtmlFromList $ zipWith3 (tableItemToHtml opts td) aligns (repeat 0) cols
208+ do contents <- sequence $ zipWith3 (tableItemToHtml opts td) aligns (repeat 0) cols
209+ return $ tr $ toHtmlFromList contents
211210
212211tableItemToHtml opts tag align' width item =
213− let attrib = [align align'] ++
214− if (width /= 0)
215− then [thestyle ("{width: " ++ show (truncate (100*width)) ++ "%;}")]
216− else [] in
217− tag ! attrib $ toHtmlFromList $ map (blockToHtml opts) item
212+ do contents <- blockListToHtml opts item
213+ let attrib = [align align'] ++
214+ if (width /= 0)
215+ then [thestyle ("{width: " ++ show (truncate (100*width)) ++ "%;}")]
216+ else []
217+ return $ tag ! attrib $ contents
218218
219−blockListToHtml :: WriterOptions -> [Block] -> Html
220−blockListToHtml opts list =
221− toHtmlFromList $ map (blockToHtml opts) list
219+blockListToHtml :: WriterOptions -> [Block] -> State Notes Html
220+blockListToHtml opts lst = mapM (blockToHtml opts) lst >>= (return . toHtmlFromList)
222221
223222-- | Convert list of Pandoc inline elements to HTML.
224−inlineListToHtml :: WriterOptions -> [Inline] -> Html
225−inlineListToHtml opts lst = toHtmlFromList $ map (inlineToHtml opts) lst
223+inlineListToHtml :: WriterOptions -> [Inline] -> State Notes Html
224+inlineListToHtml opts lst = mapM (inlineToHtml opts) lst >>= (return . toHtmlFromList)
226225
227226-- | Convert Pandoc inline element to HTML.
228−inlineToHtml :: WriterOptions -> Inline -> Html
229−inlineToHtml opts (Emph lst) =
230− emphasize $ inlineListToHtml opts lst
231−inlineToHtml opts (Strong lst) =
232− strong $ inlineListToHtml opts lst
233−inlineToHtml opts (Code str) =
234− thecode << str
235−inlineToHtml opts (Quoted SingleQuote lst) =
236− primHtmlChar "lsquo" +++ inlineListToHtml opts lst +++ primHtmlChar "rsquo"
237−inlineToHtml opts (Quoted DoubleQuote lst) =
238− primHtmlChar "ldquo" +++ inlineListToHtml opts lst +++ primHtmlChar "rdquo"
239−inlineToHtml opts EmDash = primHtmlChar "mdash"
240−inlineToHtml opts EnDash = primHtmlChar "ndash"
241−inlineToHtml opts Ellipses = primHtmlChar "hellip"
242−inlineToHtml opts Apostrophe = primHtmlChar "rsquo"
243−inlineToHtml opts (Str str) = stringToHtml str
244−inlineToHtml opts (TeX str) = stringToHtml str
245−inlineToHtml opts (HtmlInline str) = primHtml str
246−inlineToHtml opts (LineBreak) = br
247−inlineToHtml opts Space = stringToHtml " "
248−inlineToHtml opts (Link txt (Src src tit)) =
249− if (isPrefixOf "mailto:" src)
250− then obfuscateLink opts txt src
251− else anchor ! ([href src] ++ if null tit then [] else [title tit]) $
252− inlineListToHtml opts txt
253−inlineToHtml opts (Link txt (Ref ref)) =
254− '[' +++ (inlineListToHtml opts txt) +++
255− ']' +++ '[' +++ (inlineListToHtml opts ref) +++
256− ']'
257− -- this is what markdown does, for better or worse
258−inlineToHtml opts (Image alttext (Src source tit)) =
259− let alternate = renderHtmlFragment $ inlineListToHtml opts alttext in
260− image ! ([src source, title tit] ++ if null alttext then [] else [alt alternate])
261− -- note: null title is included, as in Markdown.pl
262−inlineToHtml opts (Image alternate (Ref ref)) =
263− '!' +++ inlineToHtml opts (Link alternate (Ref ref))
264−inlineToHtml opts (NoteRef ref) =
265− anchor ! [href ("#fn" ++ ref), theclass "footnoteRef", identifier ("fnref" ++ ref)] <<
266− sup << ref
227+inlineToHtml :: WriterOptions -> Inline -> State Notes Html
228+inlineToHtml opts inline =
229+ case inline of
230+ (Str str) -> return $ stringToHtml str
231+ (Space) -> return $ stringToHtml " "
232+ (LineBreak) -> return $ br
233+ (EmDash) -> return $ primHtmlChar "mdash"
234+ (EnDash) -> return $ primHtmlChar "ndash"
235+ (Ellipses) -> return $ primHtmlChar "hellip"
236+ (Apostrophe) -> return $ primHtmlChar "rsquo"
237+ (Emph lst) -> inlineListToHtml opts lst >>= (return . emphasize)
238+ (Strong lst) -> inlineListToHtml opts lst >>= (return . strong)
239+ (Code str) -> return $ thecode << str
240+ (Quoted quoteType lst) ->
241+ let (leftQuote, rightQuote) = case quoteType of
242+ SingleQuote -> (primHtmlChar "lsquo",
243+ primHtmlChar "rsquo")
244+ DoubleQuote -> (primHtmlChar "ldquo",
245+ primHtmlChar "rdquo") in
246+ do contents <- inlineListToHtml opts lst
247+ return $ leftQuote +++ contents +++ rightQuote
248+ (TeX str) -> return $ stringToHtml str
249+ (HtmlInline str) -> return $ primHtml str
250+ (Link txt (src,tit)) ->
251+ do linkText <- inlineListToHtml opts txt
252+ return $ if (isPrefixOf "mailto:" src)
253+ then obfuscateLink opts linkText src
254+ else anchor ! ([href src] ++
255+ if null tit
256+ then []
257+ else [title tit]) $
258+ linkText
259+ (Image txt (source,tit)) ->
260+ do alternate <- inlineListToHtml opts txt
261+ let alternate' = renderHtmlFragment alternate
262+ let attributes = [src source, title tit] ++
263+ if null txt then [] else [alt alternate']
264+ return $ image ! attributes
265+ -- note: null title included, as in Markdown.pl
266+ (Note contents) -> do notes <- get
267+ let number = (length notes) + 1
268+ let ref = show number
269+ htmlContents <- blockListToNote opts ref contents
270+ modify (htmlContents:) -- push contents onto front of notes
271+ return $ anchor ! [href ("#fn" ++ ref),
272+ theclass "footnoteRef",
273+ identifier ("fnref" ++ ref)] << sup << ref
274+
275+blockListToNote :: WriterOptions -> String -> [Block] -> State Notes Html
276+blockListToNote opts ref blocks =
277+ do contents <- blockListToHtml opts blocks
278+ let backlink = anchor ! [href ("#fnref" ++ ref), theclass "footnoteBacklink",
279+ title ("Jump back to footnote " ++ ref)] $
280+ (primHtmlChar "#8617")
281+ return $ li ! [identifier ("fn" ++ ref)] $ contents +++ backlink
267282
src/Text/Pandoc/Writers/LaTeX.hs+57−76
@@ -33,31 +33,28 @@ module Text.Pandoc.Writers.LaTeX (
3333import Text.Pandoc.Definition
3434import Text.Pandoc.Shared
3535import Text.Printf ( printf )
36−import List ( (\\) )
36+import Data.List ( (\\) )
3737
3838-- | Convert Pandoc to LaTeX.
3939writeLaTeX :: WriterOptions -> Pandoc -> String
4040writeLaTeX options (Pandoc meta blocks) =
41− let notes = filter isNoteBlock blocks in -- assumes all notes at outer level
4241 let body = (writerIncludeBefore options) ++
43− (concatMap (blockToLaTeX notes)
44− (replaceReferenceLinks blocks)) ++
42+ (concatMap blockToLaTeX blocks) ++
4543 (writerIncludeAfter options) in
4644 let head = if writerStandalone options
47− then latexHeader notes options meta
45+ then latexHeader options meta
4846 else "" in
4947 let foot = if writerStandalone options then "\n\\end{document}\n" else "" in
5048 head ++ body ++ foot
5149
5250-- | Insert bibliographic information into LaTeX header.
53−latexHeader :: [Block] -- ^ List of note blocks to use in resolving note refs
54− -> WriterOptions -- ^ Options, including LaTeX header
51+latexHeader :: WriterOptions -- ^ Options, including LaTeX header
5552 -> Meta -- ^ Meta with bibliographic information
5653 -> String
57−latexHeader notes options (Meta title authors date) =
54+latexHeader options (Meta title authors date) =
5855 let titletext = if null title
5956 then ""
60− else "\\title{" ++ inlineListToLaTeX notes title ++ "}\n"
57+ else "\\title{" ++ inlineListToLaTeX title ++ "}\n"
6158 authorstext = if null authors
6259 then ""
6360 else "\\author{" ++ (joinWithSep "\\\\"
@@ -99,31 +96,28 @@ deVerb ((Code str):rest) = (Str str):(deVerb rest)
9996deVerb (other:rest) = other:(deVerb rest)
10097
10198-- | Convert Pandoc block element to LaTeX.
102−blockToLaTeX :: [Block] -- ^ List of note blocks to use in resolving note refs
103− -> Block -- ^ Block to convert
99+blockToLaTeX :: Block -- ^ Block to convert
104100 -> String
105−blockToLaTeX notes Null = ""
106−blockToLaTeX notes (Plain lst) = inlineListToLaTeX notes lst ++ "\n"
107−blockToLaTeX notes (Para lst) = (inlineListToLaTeX notes lst) ++ "\n\n"
108−blockToLaTeX notes (BlockQuote lst) = "\\begin{quote}\n" ++
109− (concatMap (blockToLaTeX notes) lst) ++ "\\end{quote}\n"
110−blockToLaTeX notes (Note ref lst) = ""
111−blockToLaTeX notes (Key _ _) = ""
112−blockToLaTeX notes (CodeBlock str) = "\\begin{verbatim}\n" ++ str ++
101+blockToLaTeX Null = ""
102+blockToLaTeX (Plain lst) = inlineListToLaTeX lst ++ "\n"
103+blockToLaTeX (Para lst) = (inlineListToLaTeX lst) ++ "\n\n"
104+blockToLaTeX (BlockQuote lst) = "\\begin{quote}\n" ++
105+ (concatMap blockToLaTeX lst) ++ "\\end{quote}\n"
106+blockToLaTeX (CodeBlock str) = "\\begin{verbatim}\n" ++ str ++
113107 "\n\\end{verbatim}\n"
114−blockToLaTeX notes (RawHtml str) = ""
115−blockToLaTeX notes (BulletList lst) = "\\begin{itemize}\n" ++
116− (concatMap (listItemToLaTeX notes) lst) ++ "\\end{itemize}\n"
117−blockToLaTeX notes (OrderedList lst) = "\\begin{enumerate}\n" ++
118− (concatMap (listItemToLaTeX notes) lst) ++ "\\end{enumerate}\n"
119−blockToLaTeX notes HorizontalRule =
108+blockToLaTeX (RawHtml str) = ""
109+blockToLaTeX (BulletList lst) = "\\begin{itemize}\n" ++
110+ (concatMap listItemToLaTeX lst) ++ "\\end{itemize}\n"
111+blockToLaTeX (OrderedList lst) = "\\begin{enumerate}\n" ++
112+ (concatMap listItemToLaTeX lst) ++ "\\end{enumerate}\n"
113+blockToLaTeX HorizontalRule =
120114 "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n\n"
121−blockToLaTeX notes (Header level lst) =
115+blockToLaTeX (Header level lst) =
122116 if (level > 0) && (level <= 3)
123117 then "\\" ++ (concat (replicate (level - 1) "sub")) ++ "section{" ++
124− (inlineListToLaTeX notes (deVerb lst)) ++ "}\n\n"
125− else (inlineListToLaTeX notes lst) ++ "\n\n"
126−blockToLaTeX notes (Table caption aligns widths heads rows) =
118+ (inlineListToLaTeX (deVerb lst)) ++ "}\n\n"
119+ else (inlineListToLaTeX lst) ++ "\n\n"
120+blockToLaTeX (Table caption aligns widths heads rows) =
127121 let colWidths = map printDecimal widths
128122 colDescriptors = concat $ zipWith
129123 (\width align -> ">{\\PBS" ++
@@ -135,11 +129,11 @@ blockToLaTeX notes (Table caption aligns widths heads rows) =
135129 "\\hspace{0pt}}p{" ++ width ++
136130 "\\textwidth}")
137131 colWidths aligns
138− headers = tableRowToLaTeX notes heads
139− captionText = inlineListToLaTeX notes caption
132+ headers = tableRowToLaTeX heads
133+ captionText = inlineListToLaTeX caption
140134 tableBody = "\\begin{tabular}{" ++ colDescriptors ++ "}\n" ++
141135 headers ++ "\\hline\n" ++
142− (concatMap (tableRowToLaTeX notes) rows) ++
136+ (concatMap tableRowToLaTeX rows) ++
143137 "\\end{tabular}\n"
144138 centered str = "\\begin{center}\n" ++ str ++ "\\end{center}\n" in
145139 if null captionText
@@ -151,19 +145,18 @@ blockToLaTeX notes (Table caption aligns widths heads rows) =
151145printDecimal :: Float -> String
152146printDecimal = printf "%.2f"
153147
154−tableColumnWidths notes cols = map (length . (concatMap (blockToLaTeX notes))) cols
148+tableColumnWidths cols = map (length . (concatMap blockToLaTeX)) cols
155149
156−tableRowToLaTeX notes cols = joinWithSep " & " (map (concatMap (blockToLaTeX notes)) cols) ++ "\\\\\n"
150+tableRowToLaTeX cols = joinWithSep " & " (map (concatMap blockToLaTeX) cols) ++ "\\\\\n"
157151
158−listItemToLaTeX notes list = "\\item " ++
159− (concatMap (blockToLaTeX notes) list)
152+listItemToLaTeX list = "\\item " ++
153+ (concatMap blockToLaTeX list)
160154
161155-- | Convert list of inline elements to LaTeX.
162−inlineListToLaTeX :: [Block] -- ^ List of note blocks to use in resolving note refs
163− -> [Inline] -- ^ Inlines to convert
156+inlineListToLaTeX :: [Inline] -- ^ Inlines to convert
164157 -> String
165−inlineListToLaTeX notes lst =
166− concatMap (inlineToLaTeX notes) lst
158+inlineListToLaTeX lst =
159+ concatMap inlineToLaTeX lst
167160
168161isQuoted :: Inline -> Bool
169162isQuoted (Quoted _ _) = True
@@ -171,47 +164,35 @@ isQuoted Apostrophe = True
171164isQuoted _ = False
172165
173166-- | Convert inline element to LaTeX
174−inlineToLaTeX :: [Block] -- ^ List of note blocks to use in resolving note refs
175− -> Inline -- ^ Inline to convert
167+inlineToLaTeX :: Inline -- ^ Inline to convert
176168 -> String
177−inlineToLaTeX notes (Emph lst) = "\\emph{" ++
178− (inlineListToLaTeX notes (deVerb lst)) ++ "}"
179−inlineToLaTeX notes (Strong lst) = "\\textbf{" ++
180− (inlineListToLaTeX notes (deVerb lst)) ++ "}"
181−inlineToLaTeX notes (Code str) = "\\verb" ++ [chr] ++ stuffing ++ [chr]
169+inlineToLaTeX (Emph lst) = "\\emph{" ++
170+ (inlineListToLaTeX (deVerb lst)) ++ "}"
171+inlineToLaTeX (Strong lst) = "\\textbf{" ++
172+ (inlineListToLaTeX (deVerb lst)) ++ "}"
173+inlineToLaTeX (Code str) = "\\verb" ++ [chr] ++ stuffing ++ [chr]
182174 where stuffing = str
183175 chr = ((enumFromTo '!' '~') \\ stuffing) !! 0
184−inlineToLaTeX notes (Quoted SingleQuote lst) =
176+inlineToLaTeX (Quoted SingleQuote lst) =
185177 let s1 = if (not (null lst)) && (isQuoted (head lst)) then "\\," else ""
186178 s2 = if (not (null lst)) && (isQuoted (last lst)) then "\\," else "" in
187− "`" ++ s1 ++ inlineListToLaTeX notes lst ++ s2 ++ "'"
188−inlineToLaTeX notes (Quoted DoubleQuote lst) =
179+ "`" ++ s1 ++ inlineListToLaTeX lst ++ s2 ++ "'"
180+inlineToLaTeX (Quoted DoubleQuote lst) =
189181 let s1 = if (not (null lst)) && (isQuoted (head lst)) then "\\," else ""
190182 s2 = if (not (null lst)) && (isQuoted (last lst)) then "\\," else "" in
191− "``" ++ s1 ++ inlineListToLaTeX notes lst ++ s2 ++ "''"
192−inlineToLaTeX notes Apostrophe = "'"
193−inlineToLaTeX notes EmDash = "---"
194−inlineToLaTeX notes EnDash = "--"
195−inlineToLaTeX notes Ellipses = "\\ldots{}"
196−inlineToLaTeX notes (Str str) = stringToLaTeX str
197−inlineToLaTeX notes (TeX str) = str
198−inlineToLaTeX notes (HtmlInline str) = ""
199−inlineToLaTeX notes (LineBreak) = "\\\\\n"
200−inlineToLaTeX notes Space = " "
201−inlineToLaTeX notes (Link text (Src src tit)) =
202− "\\href{" ++ src ++ "}{" ++ (inlineListToLaTeX notes (deVerb text)) ++ "}"
203−inlineToLaTeX notes (Link text (Ref ref)) = "[" ++
204− (inlineListToLaTeX notes text) ++ "][" ++ (inlineListToLaTeX notes ref) ++
205− "]" -- this is what markdown does, for better or worse
206−inlineToLaTeX notes (Image alternate (Src source tit)) =
183+ "``" ++ s1 ++ inlineListToLaTeX lst ++ s2 ++ "''"
184+inlineToLaTeX Apostrophe = "'"
185+inlineToLaTeX EmDash = "---"
186+inlineToLaTeX EnDash = "--"
187+inlineToLaTeX Ellipses = "\\ldots{}"
188+inlineToLaTeX (Str str) = stringToLaTeX str
189+inlineToLaTeX (TeX str) = str
190+inlineToLaTeX (HtmlInline str) = ""
191+inlineToLaTeX (LineBreak) = "\\\\\n"
192+inlineToLaTeX Space = " "
193+inlineToLaTeX (Link text (src, tit)) =
194+ "\\href{" ++ src ++ "}{" ++ (inlineListToLaTeX (deVerb text)) ++ "}"
195+inlineToLaTeX (Image alternate (source, tit)) =
207196 "\\includegraphics{" ++ source ++ "}"
208−inlineToLaTeX notes (Image alternate (Ref ref)) =
209− "![" ++ (inlineListToLaTeX notes alternate) ++ "][" ++
210− (inlineListToLaTeX notes ref) ++ "]"
211−inlineToLaTeX [] (NoteRef ref) = ""
212−inlineToLaTeX ((Note firstref firstblocks):rest) (NoteRef ref) =
213− if (firstref == ref)
214− then "\\footnote{" ++ (stripTrailingNewlines
215− (concatMap (blockToLaTeX rest) firstblocks)) ++ "}"
216− else inlineToLaTeX rest (NoteRef ref)
217−
197+inlineToLaTeX (Note contents) =
198+ "\\footnote{" ++ (stripTrailingNewlines $ concatMap blockToLaTeX contents) ++ "}"
src/Text/Pandoc/Writers/Markdown.hs+204−144
@@ -34,19 +34,71 @@ module Text.Pandoc.Writers.Markdown (
3434 ) where
3535import Text.Pandoc.Definition
3636import Text.Pandoc.Shared
37−import Data.List ( group, isPrefixOf, drop )
37+import Data.List ( group, isPrefixOf, drop, find )
3838import Text.PrettyPrint.HughesPJ hiding ( Str )
39+import Control.Monad.State
40+
41+type Notes = [[Block]]
42+type Refs = KeyTable
43+type WriterState = (Notes, Refs)
3944
4045-- | Convert Pandoc to Markdown.
4146writeMarkdown :: WriterOptions -> Pandoc -> String
42−writeMarkdown options (Pandoc meta blocks) =
43− let body = text (writerIncludeBefore options) <>
44− vcat (map (blockToMarkdown (writerTabStop options))
45− (formatKeys blocks)) $$ text (writerIncludeAfter options) in
46− let head = if (writerStandalone options)
47− then ((metaToMarkdown meta) $$ text (writerHeader options))
48− else empty in
49− render $ head <> body
47+writeMarkdown opts document =
48+ render $ evalState (pandocToMarkdown opts document) ([],[])
49+
50+-- | Return markdown representation of document.
51+pandocToMarkdown :: WriterOptions -> Pandoc -> State WriterState Doc
52+pandocToMarkdown opts (Pandoc meta blocks) = do
53+ let before = writerIncludeBefore opts
54+ let after = writerIncludeAfter opts
55+ before' = if null before then empty else text before
56+ after' = if null after then empty else text after
57+ metaBlock <- metaToMarkdown opts meta
58+ let head = if (writerStandalone opts)
59+ then metaBlock $$ text (writerHeader opts)
60+ else empty
61+ body <- blockListToMarkdown opts blocks
62+ (notes, _) <- get
63+ notes' <- notesToMarkdown opts (reverse notes)
64+ (_, refs) <- get -- note that the notes may contain refs
65+ refs' <- keyTableToMarkdown opts (reverse refs)
66+ return $ head <> (before' $$ body <> text "\n" $$
67+ notes' <> text "\n" $$ refs' $$ after')
68+
69+-- | Return markdown representation of reference key table.
70+keyTableToMarkdown :: WriterOptions -> KeyTable -> State WriterState Doc
71+keyTableToMarkdown opts refs =
72+ mapM (keyToMarkdown opts) refs >>= (return . vcat)
73+
74+-- | Return markdown representation of a reference key.
75+keyToMarkdown :: WriterOptions
76+ -> ([Inline], (String, String))
77+ -> State WriterState Doc
78+keyToMarkdown opts (label, (src, tit)) = do
79+ label' <- inlineListToMarkdown opts label
80+ let tit' = if null tit then empty else text $ " \"" ++ tit ++ "\""
81+ return $ text " " <> char '[' <> label' <> char ']' <> text ": " <>
82+ text src <> tit'
83+
84+-- | Return markdown representation of notes.
85+notesToMarkdown :: WriterOptions -> [[Block]] -> State WriterState Doc
86+notesToMarkdown opts notes =
87+ mapM (\(num, note) -> noteToMarkdown opts num note) (zip [1..] notes) >>=
88+ (return . vcat)
89+
90+-- | Return markdown representation of a note.
91+noteToMarkdown :: WriterOptions -> Int -> [Block] -> State WriterState Doc
92+noteToMarkdown opts num note = do
93+ contents <- blockListToMarkdown opts note
94+ let marker = text "[^" <> text (show num) <> text "]:"
95+ return $ hang marker (writerTabStop opts) contents
96+
97+wrappedMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
98+wrappedMarkdown opts sect = do
99+ let chunks = splitBy Space sect
100+ chunks' <- mapM (inlineListToMarkdown opts) chunks
101+ return $ fsep chunks'
50102
51103-- | Escape nonbreaking space as &nbsp; entity
52104escapeNbsp "" = ""
@@ -59,155 +111,163 @@ escapeNbsp str =
59111escapeString :: String -> String
60112escapeString = backslashEscape "`<\\*_^" . escapeNbsp
61113
62−-- | Take list of inline elements and return wrapped doc.
63−wrappedMarkdown :: [Inline] -> Doc
64−wrappedMarkdown lst =
65− let wrapSection sec = fsep $ map inlineListToMarkdown $ (splitBy Space sec)
66− wrappedSecs = map wrapSection $ splitBy LineBreak lst
67− wrappedSecs' = foldr (\s rest -> if not (null rest)
68− then (s <> text " "):rest
69− else s:rest) [] wrappedSecs in
70− vcat wrappedSecs'
71−
72−-- | Insert Blank block between key and non-key
73−formatKeys :: [Block] -> [Block]
74−formatKeys [] = []
75−formatKeys [x] = [x]
76−formatKeys ((Key x1 y1):(Key x2 y2):rest) =
77− (Key x1 y1):(formatKeys ((Key x2 y2):rest))
78−formatKeys ((Key x1 y1):rest) = (Key x1 y1):(Plain [Str ""]):(formatKeys rest)
79−formatKeys (x:(Key x1 y1):rest) = x:(Plain [Str ""]):(formatKeys ((Key x1 y1):rest))
80−formatKeys (x:rest) = x:(formatKeys rest)
81−
82114-- | Convert bibliographic information into Markdown header.
83−metaToMarkdown :: Meta -> Doc
84−metaToMarkdown (Meta [] [] "") = empty
85−metaToMarkdown (Meta title [] "") = (titleToMarkdown title) <> (text "\n")
86−metaToMarkdown (Meta title authors "") = (titleToMarkdown title) <>
87− (text "\n") <> (authorsToMarkdown authors) <> (text "\n")
88−metaToMarkdown (Meta title authors date) = (titleToMarkdown title) <>
89− (text "\n") <> (authorsToMarkdown authors) <> (text "\n") <>
90− (dateToMarkdown date) <> (text "\n")
115+metaToMarkdown :: WriterOptions -> Meta -> State WriterState Doc
116+metaToMarkdown opts (Meta title authors date) = do
117+ title' <- titleToMarkdown opts title
118+ authors' <- authorsToMarkdown authors
119+ date' <- dateToMarkdown date
120+ return $ title' <> authors' <> date'
91121
92−titleToMarkdown :: [Inline] -> Doc
93−titleToMarkdown lst = text "% " <> (inlineListToMarkdown lst)
122+titleToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
123+titleToMarkdown opts [] = return empty
124+titleToMarkdown opts lst = do
125+ contents <- inlineListToMarkdown opts lst
126+ return $ text "% " <> contents <> text "\n"
94127
95−authorsToMarkdown :: [String] -> Doc
96−authorsToMarkdown lst =
97− text "% " <> text (joinWithSep ", " (map escapeString lst))
128+authorsToMarkdown :: [String] -> State WriterState Doc
129+authorsToMarkdown [] = return empty
130+authorsToMarkdown lst = return $
131+ text "% " <> text (joinWithSep ", " (map escapeString lst)) <> text "\n"
98132
99−dateToMarkdown :: String -> Doc
100−dateToMarkdown str = text "% " <> text (escapeString str)
133+dateToMarkdown :: String -> State WriterState Doc
134+dateToMarkdown [] = return empty
135+dateToMarkdown str = return $ text "% " <> text (escapeString str) <> text "\n"
101136
102137-- | Convert Pandoc block element to markdown.
103−blockToMarkdown :: Int -- ^ Tab stop
104− -> Block -- ^ Block element
105− -> Doc
106−blockToMarkdown tabStop Null = empty
107−blockToMarkdown tabStop (Plain lst) = wrappedMarkdown lst
108−blockToMarkdown tabStop (Para lst) = (wrappedMarkdown lst) <> (text "\n")
109−blockToMarkdown tabStop (BlockQuote lst) =
110− (vcat $ map (\line -> (text "> ") <> (text line)) $ lines $ render $ vcat $
111− map (blockToMarkdown tabStop) lst) <> (text "\n")
112−blockToMarkdown tabStop (Note ref lst) =
113− let lns = lines $ render $ vcat $ map (blockToMarkdown tabStop) lst in
114− if null lns
115− then empty
116− else let first = head lns
117− rest = tail lns in
118− text ("[^" ++ (escapeString ref) ++ "]: ") <> (text first) $$
119− (vcat $ map (\line -> (text " ") <> (text line)) rest) <>
120− text "\n"
121−blockToMarkdown tabStop (Key txt (Src src tit)) =
122− text " " <> char '[' <> inlineListToMarkdown txt <> char ']' <>
123− text ": " <> text src <>
124− if tit /= "" then text (" \"" ++ tit ++ "\"") else empty
125−blockToMarkdown tabStop (CodeBlock str) =
126− (nest tabStop $ vcat $ map text (lines str)) <> text "\n"
127−blockToMarkdown tabStop (RawHtml str) = text str
128−blockToMarkdown tabStop (BulletList lst) =
129− vcat (map (bulletListItemToMarkdown tabStop) lst) <> text "\n"
130−blockToMarkdown tabStop (OrderedList lst) =
131− vcat (zipWith (orderedListItemToMarkdown tabStop)
132− (enumFromTo 1 (length lst)) lst) <> text "\n"
133−blockToMarkdown tabStop HorizontalRule = text "\n* * * * *\n"
134−blockToMarkdown tabStop (Header level lst) = text ((replicate level '#') ++
135− " ") <> (inlineListToMarkdown lst) <> (text "\n")
136−blockToMarkdown tabStop (Table caption _ _ headers rows) =
137− blockToMarkdown tabStop (Para [Str "pandoc: TABLE unsupported in Markdown writer"])
138−
139−
140−bulletListItemToMarkdown tabStop list =
141− hang (text "- ") tabStop (vcat (map (blockToMarkdown tabStop) list))
138+blockToMarkdown :: WriterOptions -- ^ Options
139+ -> Block -- ^ Block element
140+ -> State WriterState Doc
141+blockToMarkdown opts Null = return empty
142+blockToMarkdown opts (Plain inlines) = wrappedMarkdown opts inlines
143+blockToMarkdown opts (Para inlines) = do
144+ contents <- wrappedMarkdown opts inlines
145+ return $ contents <> text "\n"
146+blockToMarkdown opts (RawHtml str) = return $ text str
147+blockToMarkdown opts HorizontalRule = return $ text "\n* * * * *\n"
148+blockToMarkdown opts (Header level inlines) = do
149+ contents <- inlineListToMarkdown opts inlines
150+ return $ text ((replicate level '#') ++ " ") <> contents <> text "\n"
151+blockToMarkdown opts (CodeBlock str) = return $
152+ (nest (writerTabStop opts) $ vcat $ map text (lines str)) <> text "\n"
153+blockToMarkdown opts (BlockQuote blocks) = do
154+ contents <- blockListToMarkdown opts blocks
155+ let quotedContents = unlines $ map ("> " ++) $ lines $ render contents
156+ return $ text quotedContents
157+blockToMarkdown opts (Table caption _ _ headers rows) = blockToMarkdown opts
158+ (Para [Str "pandoc: TABLE unsupported in Markdown writer"])
159+blockToMarkdown opts (BulletList items) = do
160+ contents <- mapM (bulletListItemToMarkdown opts) items
161+ return $ (vcat contents) <> text "\n"
162+blockToMarkdown opts (OrderedList items) = do
163+ contents <- mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
164+ zip [1..] items
165+ return $ (vcat contents) <> text "\n"
166+
167+-- | Convert bullet list item (list of blocks) to markdown.
168+bulletListItemToMarkdown :: WriterOptions -> [Block] -> State WriterState Doc
169+bulletListItemToMarkdown opts items = do
170+ contents <- blockListToMarkdown opts items
171+ return $ hang (text "- ") (writerTabStop opts) contents
142172
143173-- | Convert ordered list item (a list of blocks) to markdown.
144−orderedListItemToMarkdown :: Int -- ^ tab stop
145− -> Int -- ^ ordinal number of list item
146− -> [Block] -- ^ list item (list of blocks)
147− -> Doc
148−orderedListItemToMarkdown tabStop num list =
149− hang (text ((show num) ++ "." ++ spacer)) tabStop
150− (vcat (map (blockToMarkdown tabStop) list))
151− where spacer = if (num < 10) then " " else ""
174+orderedListItemToMarkdown :: WriterOptions -- ^ options
175+ -> Int -- ^ ordinal number of list item
176+ -> [Block] -- ^ list item (list of blocks)
177+ -> State WriterState Doc
178+orderedListItemToMarkdown opts num items = do
179+ contents <- blockListToMarkdown opts items
180+ let spacer = if (num < 10) then " " else ""
181+ return $ hang (text ((show num) ++ "." ++ spacer)) (writerTabStop opts)
182+ contents
183+
184+-- | Convert list of Pandoc block elements to markdown.
185+blockListToMarkdown :: WriterOptions -- ^ Options
186+ -> [Block] -- ^ List of block elements
187+ -> State WriterState Doc
188+blockListToMarkdown opts blocks =
189+ mapM (blockToMarkdown opts) blocks >>= (return . vcat)
190+
191+-- | Get reference for target; if none exists, create unique one and return.
192+-- Prefer label if possible; otherwise, generate a unique key.
193+getReference :: [Inline] -> Target -> State WriterState [Inline]
194+getReference label (src, tit) = do
195+ (_,refs) <- get
196+ case find ((== (src, tit)) . snd) refs of
197+ Just (ref, _) -> return ref
198+ Nothing -> do
199+ let label' = case find ((== label) . fst) refs of
200+ Just _ -> -- label is used; generate numerical label
201+ case find (\n -> not (any (== [Str (show n)])
202+ (map fst refs))) [1..10000] of
203+ Just x -> [Str (show x)]
204+ Nothing -> error "no unique label"
205+ Nothing -> label
206+ modify (\(notes, refs) -> (notes, (label', (src,tit)):refs))
207+ return label'
152208
153209-- | Convert list of Pandoc inline elements to markdown.
154−inlineListToMarkdown :: [Inline] -> Doc
155−inlineListToMarkdown lst = hcat $ map inlineToMarkdown lst
210+inlineListToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
211+inlineListToMarkdown opts lst = mapM (inlineToMarkdown opts) lst >>= (return . hcat)
156212
157213-- | Convert Pandoc inline element to markdown.
158−inlineToMarkdown :: Inline -> Doc
159−inlineToMarkdown (Emph lst) = text "*" <>
160− (inlineListToMarkdown lst) <> text "*"
161−inlineToMarkdown (Strong lst) = text "**" <>
162− (inlineListToMarkdown lst) <> text "**"
163−inlineToMarkdown (Quoted SingleQuote lst) = char '\'' <>
164− (inlineListToMarkdown lst) <> char '\''
165−inlineToMarkdown (Quoted DoubleQuote lst) = char '"' <>
166− (inlineListToMarkdown lst) <> char '"'
167−inlineToMarkdown EmDash = text "--"
168−inlineToMarkdown EnDash = char '-'
169−inlineToMarkdown Apostrophe = char '\''
170−inlineToMarkdown Ellipses = text "..."
171−inlineToMarkdown (Code str) =
214+inlineToMarkdown :: WriterOptions -> Inline -> State WriterState Doc
215+inlineToMarkdown opts (Emph lst) = do
216+ contents <- inlineListToMarkdown opts lst
217+ return $ text "*" <> contents <> text "*"
218+inlineToMarkdown opts (Strong lst) = do
219+ contents <- inlineListToMarkdown opts lst
220+ return $ text "**" <> contents <> text "**"
221+inlineToMarkdown opts (Quoted SingleQuote lst) = do
222+ contents <- inlineListToMarkdown opts lst
223+ return $ char '\'' <> contents <> char '\''
224+inlineToMarkdown opts (Quoted DoubleQuote lst) = do
225+ contents <- inlineListToMarkdown opts lst
226+ return $ char '"' <> contents <> char '"'
227+inlineToMarkdown opts EmDash = return $ text "--"
228+inlineToMarkdown opts EnDash = return $ char '-'
229+inlineToMarkdown opts Apostrophe = return $ char '\''
230+inlineToMarkdown opts Ellipses = return $ text "..."
231+inlineToMarkdown opts (Code str) =
172232 let tickGroups = filter (\s -> '`' `elem` s) $ group str
173233 longest = if null tickGroups
174234 then 0
175235 else maximum $ map length tickGroups
176236 marker = replicate (longest + 1) '`'
177− spacer = if (longest == 0) then "" else " " in
178− text (marker ++ spacer ++ str ++ spacer ++ marker)
179−inlineToMarkdown (Str str) = text $ escapeString str
180−inlineToMarkdown (TeX str) = text str
181−inlineToMarkdown (HtmlInline str) = text str
182−inlineToMarkdown (LineBreak) = text " \n"
183−inlineToMarkdown Space = char ' '
184−inlineToMarkdown (Link txt (Src src tit)) =
185− let linktext = if (null txt) || (txt == [Str ""])
186− then text "link"
187− else inlineListToMarkdown txt
188− linktitle = if null tit
189− then empty
190− else text (" \"" ++ tit ++ "\"")
191− srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src in
192− if (null tit) && (txt == [Str srcSuffix])
193− then char '<' <> text srcSuffix <> char '>'
194− else char '[' <> linktext <> char ']' <> char '(' <> text src <>
195− linktitle <> char ')'
196−inlineToMarkdown (Link txt (Ref ref)) =
197− let first = char '[' <> inlineListToMarkdown txt <> char ']'
198− second = if (txt == ref)
199− then text "[]"
200− else char '[' <> inlineListToMarkdown ref <> char ']' in
201− first <> second
202−inlineToMarkdown (Image alternate (Src source tit)) =
203− let alt = if (null alternate) || (alternate == [Str ""])
204− then text "image"
205− else inlineListToMarkdown alternate in
206− char '!' <> char '[' <> alt <> char ']' <> char '(' <> text source <>
207− (if tit /= ""
208− then text (" \"" ++ tit ++ "\"")
209− else empty) <> char ')'
210−inlineToMarkdown (Image alternate (Ref ref)) =
211− char '!' <> inlineToMarkdown (Link alternate (Ref ref))
212−inlineToMarkdown (NoteRef ref) =
213− text "[^" <> text (escapeString ref) <> char ']'
237+ spacer = if (longest == 0) then "" else " " in
238+ return $ text (marker ++ spacer ++ str ++ spacer ++ marker)
239+inlineToMarkdown opts (Str str) = return $ text $ escapeString str
240+inlineToMarkdown opts (TeX str) = return $ text str
241+inlineToMarkdown opts (HtmlInline str) = return $ text str
242+inlineToMarkdown opts (LineBreak) = return $ text " \n"
243+inlineToMarkdown opts Space = return $ char ' '
244+inlineToMarkdown opts (Link txt (src, tit)) = do
245+ linktext <- inlineListToMarkdown opts txt
246+ let linktitle = if null tit then empty else text $ " \"" ++ tit ++ "\""
247+ let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
248+ let useRefLinks = writerReferenceLinks opts
249+ let useAuto = null tit && txt == [Str srcSuffix]
250+ ref <- if useRefLinks then getReference txt (src, tit) else return []
251+ reftext <- inlineListToMarkdown opts ref
252+ return $ if useAuto
253+ then char '<' <> text srcSuffix <> char '>'
254+ else if useRefLinks
255+ then let first = char '[' <> linktext <> char ']'
256+ second = if txt == ref
257+ then text "[]"
258+ else char '[' <> reftext <> char ']'
259+ in first <> second
260+ else char '[' <> linktext <> char ']' <>
261+ char '(' <> text src <> linktitle <> char ')'
262+inlineToMarkdown opts (Image alternate (source, tit)) = do
263+ let txt = if (null alternate) || (alternate == [Str ""]) ||
264+ (alternate == [Str source]) -- to prevent autolinks
265+ then [Str "image"]
266+ else alternate
267+ linkPart <- inlineToMarkdown opts (Link txt (source, tit))
268+ return $ char '!' <> linkPart
269+inlineToMarkdown opts (Note contents) = do
270+ modify (\(notes, refs) -> (contents:notes, refs)) -- add to notes in state
271+ (notes, _) <- get
272+ let ref = show $ (length notes)
273+ return $ text "[^" <> text ref <> char ']'
src/Text/Pandoc/Writers/RST.hs+233−192
@@ -30,204 +30,245 @@ Conversion of 'Pandoc' documents to reStructuredText.
3030reStructuredText: <http://docutils.sourceforge.net/rst.html>
3131-}
3232module Text.Pandoc.Writers.RST (
33− writeRST
34− ) where
33+ writeRST
34+ ) where
3535import Text.Pandoc.Definition
36−import Text.Pandoc.Shared
37−import List ( nubBy )
36+import Text.Pandoc.Shared
37+import Data.List ( group, isPrefixOf, drop, find )
3838import Text.PrettyPrint.HughesPJ hiding ( Str )
39+import Control.Monad.State
3940
40−-- | Convert Pandoc to reStructuredText.
41+type Notes = [[Block]]
42+type Refs = KeyTable
43+type WriterState = (Notes, Refs, Refs) -- first Refs is links, second pictures
44+
45+-- | Convert Pandoc to RST.
4146writeRST :: WriterOptions -> Pandoc -> String
42−writeRST options (Pandoc meta blocks) =
43− let (main, refs) = unzip $ map (blockToRST (writerTabStop options))
44− (reformatBlocks $ replaceReferenceLinks blocks)
45− top = if (writerStandalone options)
46− then (metaToRST meta) $$ text (writerHeader options)
47− else empty in
48− -- remove duplicate keys
49− let refs' = nubBy (\x y -> (render x) == (render y)) refs in
50− let body = text (writerIncludeBefore options) <>
51− vcat main $$ text (writerIncludeAfter options) in
52− render $ top <> body $$ vcat refs' $$ text "\n"
53−
54−-- | Escape special RST characters.
47+writeRST opts document =
48+ render $ evalState (pandocToRST opts document) ([],[],[])
49+
50+-- | Return RST representation of document.
51+pandocToRST :: WriterOptions -> Pandoc -> State WriterState Doc
52+pandocToRST opts (Pandoc meta blocks) = do
53+ let before = writerIncludeBefore opts
54+ let after = writerIncludeAfter opts
55+ before' = if null before then empty else text before
56+ after' = if null after then empty else text after
57+ metaBlock <- metaToRST opts meta
58+ let head = if (writerStandalone opts)
59+ then metaBlock $$ text (writerHeader opts)
60+ else empty
61+ body <- blockListToRST opts blocks
62+ (notes, _, _) <- get
63+ notes' <- notesToRST opts (reverse notes)
64+ (_, refs, pics) <- get -- note that the notes may contain refs
65+ refs' <- keyTableToRST opts (reverse refs)
66+ pics' <- pictTableToRST opts (reverse pics)
67+ return $ head <> (before' $$ body $$ notes' <> text "\n" $$ refs' $$
68+ pics' $$ after')
69+
70+-- | Return RST representation of reference key table.
71+keyTableToRST :: WriterOptions -> KeyTable -> State WriterState Doc
72+keyTableToRST opts refs =
73+ mapM (keyToRST opts) refs >>= (return . vcat)
74+
75+-- | Return RST representation of a reference key.
76+keyToRST :: WriterOptions
77+ -> ([Inline], (String, String))
78+ -> State WriterState Doc
79+keyToRST opts (label, (src, tit)) = do
80+ label' <- inlineListToRST opts label
81+ return $ text ".. _" <> label' <> text ": " <> text src
82+
83+-- | Return RST representation of notes.
84+notesToRST :: WriterOptions -> [[Block]] -> State WriterState Doc
85+notesToRST opts notes =
86+ mapM (\(num, note) -> noteToRST opts num note) (zip [1..] notes) >>=
87+ (return . vcat)
88+
89+-- | Return RST representation of a note.
90+noteToRST :: WriterOptions -> Int -> [Block] -> State WriterState Doc
91+noteToRST opts num note = do
92+ contents <- blockListToRST opts note
93+ let marker = text ".. [" <> text (show num) <> text "] "
94+ return $ hang marker 3 contents
95+
96+-- | Return RST representation of picture reference table.
97+pictTableToRST :: WriterOptions -> KeyTable -> State WriterState Doc
98+pictTableToRST opts refs =
99+ mapM (pictToRST opts) refs >>= (return . vcat)
100+
101+-- | Return RST representation of a picture substitution reference.
102+pictToRST :: WriterOptions
103+ -> ([Inline], (String, String))
104+ -> State WriterState Doc
105+pictToRST opts (label, (src, _)) = do
106+ label' <- inlineListToRST opts label
107+ return $ text ".. " <> char '|' <> label' <> char '|' <> text " image:: " <>
108+ text src
109+
110+-- | Take list of inline elements and return wrapped doc.
111+wrappedRST :: WriterOptions -> [Inline] -> State WriterState Doc
112+wrappedRST opts inlines =
113+ mapM (wrappedRSTSection opts) (splitBy LineBreak inlines) >>=
114+ (return . vcat)
115+
116+wrappedRSTSection :: WriterOptions -> [Inline] -> State WriterState Doc
117+wrappedRSTSection opts sect = do
118+ let chunks = splitBy Space sect
119+ chunks' <- mapM (inlineListToRST opts) chunks
120+ return $ fsep chunks'
121+
122+-- | Escape special characters for RST.
55123escapeString :: String -> String
56124escapeString = backslashEscape "`\\|*_"
57125
58−-- | Convert list of inline elements into one 'Doc' of wrapped text
59−-- and another containing references.
60−wrappedRST :: [Inline] -> (Doc, Doc)
61−wrappedRST lst =
62− let wrap_section sec = fsep $ map (fst . inlineListToRST) $
63− (splitBy Space sec) in
64− ((vcat $ map wrap_section $ (splitBy LineBreak lst)),
65− vcat $ map (snd . inlineToRST) lst)
66−
67−-- | Remove reference keys, and make sure there are blanks before each list.
68−reformatBlocks :: [Block] -> [Block]
69−reformatBlocks [] = []
70−reformatBlocks ((Plain x):(OrderedList y):rest) =
71− (Para x):(reformatBlocks ((OrderedList y):rest))
72−reformatBlocks ((Plain x):(BulletList y):rest) =
73− (Para x):(reformatBlocks ((BulletList y):rest))
74−reformatBlocks ((OrderedList x):rest) =
75− (OrderedList (map reformatBlocks x)):(reformatBlocks rest)
76−reformatBlocks ((BulletList x):rest) =
77− (BulletList (map reformatBlocks x)):(reformatBlocks rest)
78−reformatBlocks ((BlockQuote x):rest) =
79− (BlockQuote (reformatBlocks x)):(reformatBlocks rest)
80−reformatBlocks ((Note ref x):rest) =
81− (Note ref (reformatBlocks x)):(reformatBlocks rest)
82−reformatBlocks ((Key x1 y1):rest) = reformatBlocks rest
83−reformatBlocks (x:rest) = x:(reformatBlocks rest)
84−
85−-- | Convert bibliographic information to 'Doc'.
86−metaToRST :: Meta -> Doc
87−metaToRST (Meta title authors date) =
88− (titleToRST title) <> (authorsToRST authors) <> (dateToRST date)
89−
90−-- | Convert title to 'Doc'.
91−titleToRST :: [Inline] -> Doc
92−titleToRST [] = empty
93−titleToRST lst =
94− let title = fst $ inlineListToRST lst in
95− let titleLength = length $ render title in
96− let border = text (replicate titleLength '=') in
97− border <> char '\n' <> title <> char '\n' <> border <> text "\n\n"
98−
99−-- | Convert author list to 'Doc'.
100−authorsToRST :: [String] -> Doc
101−authorsToRST [] = empty
102−authorsToRST (first:rest) = text ":Author: " <> text first <>
103− char '\n' <> (authorsToRST rest)
104−
105−-- | Convert date to 'Doc'.
106−dateToRST :: String -> Doc
107−dateToRST [] = empty
108−dateToRST str = text ":Date: " <> text (escapeString str) <> char '\n'
109−
110−-- | Convert Pandoc block element to a 'Doc' containing the main text and
111−-- another one containing any references.
112−blockToRST :: Int -- ^ tab stop
113− -> Block -- ^ block element to convert
114− -> (Doc, Doc) -- ^ first element is text, second is references for end of file
115−blockToRST tabStop Null = (empty, empty)
116−blockToRST tabStop (Plain lst) = wrappedRST lst
117−blockToRST tabStop (Para [TeX str]) = -- raw latex block
126+-- | Convert bibliographic information into RST header.
127+metaToRST :: WriterOptions -> Meta -> State WriterState Doc
128+metaToRST opts (Meta title authors date) = do
129+ title' <- titleToRST opts title
130+ authors' <- authorsToRST authors
131+ date' <- dateToRST date
132+ return $ title' <> authors' <> date'
133+
134+titleToRST :: WriterOptions -> [Inline] -> State WriterState Doc
135+titleToRST opts [] = return empty
136+titleToRST opts lst = do
137+ contents <- inlineListToRST opts lst
138+ let titleLength = length $ render contents
139+ let border = text (replicate titleLength '=')
140+ return $ border <> char '\n' <> contents <> char '\n' <> border <> text "\n\n"
141+
142+authorsToRST :: [String] -> State WriterState Doc
143+authorsToRST [] = return empty
144+authorsToRST (first:rest) = do
145+ rest' <- authorsToRST rest
146+ return $ text ":Author: " <> text first <> char '\n' <> rest'
147+
148+dateToRST :: String -> State WriterState Doc
149+dateToRST [] = return empty
150+dateToRST str = return $ text ":Date: " <> text (escapeString str) <> char '\n'
151+
152+-- | Convert Pandoc block element to RST.
153+blockToRST :: WriterOptions -- ^ Options
154+ -> Block -- ^ Block element
155+ -> State WriterState Doc
156+blockToRST opts Null = return empty
157+blockToRST opts (Plain inlines) = wrappedRST opts inlines
158+blockToRST opts (Para [TeX str]) =
118159 let str' = if (endsWith '\n' str) then (str ++ "\n") else (str ++ "\n\n") in
119− (hang (text "\n.. raw:: latex\n") 3 (vcat $ map text (lines str')), empty)
120−blockToRST tabStop (Para lst) = ( (fst $ wrappedRST lst) <> (text "\n"),
121− snd $ wrappedRST lst )
122−blockToRST tabStop (BlockQuote lst) =
123− let (main, refs) = unzip $ map (blockToRST tabStop) lst in
124− ((nest tabStop $ vcat $ main) <> text "\n", vcat refs)
125−blockToRST tabStop (Note ref blocks) =
126− let (main, refs) = unzip $ map (blockToRST tabStop) blocks in
127− ((hang (text ".. [" <> text (escapeString ref) <> text "] ") 3 (vcat main)),
128− vcat refs)
129−blockToRST tabStop (Key txt (Src src tit)) =
130− (text "ERROR - KEY FOUND", empty) -- shouldn't have a key here
131−blockToRST tabStop (CodeBlock str) = (hang (text "::\n") tabStop
132− (vcat $ map text (lines ('\n':(str ++ "\n\n")))), empty)
133−blockToRST tabStop (RawHtml str) =
160+ return $ hang (text "\n.. raw:: latex\n") 3 (vcat $ map text (lines str'))
161+blockToRST opts (Para inlines) = do
162+ contents <- wrappedRST opts inlines
163+ return $ contents <> text "\n"
164+blockToRST opts (RawHtml str) =
134165 let str' = if (endsWith '\n' str) then (str ++ "\n") else (str ++ "\n\n") in
135− (hang (text "\n.. raw:: html\n") 3 (vcat $ map text (lines str')), empty)
136−blockToRST tabStop (BulletList lst) =
137− let (main, refs) = unzip $ map (bulletListItemToRST tabStop) lst in
138− (vcat main <> text "\n", vcat refs)
139−blockToRST tabStop (OrderedList lst) =
140− let (main, refs) = unzip $ zipWith (orderedListItemToRST tabStop)
141− (enumFromTo 1 (length lst)) lst in
142− (vcat main <> text "\n", vcat refs)
143−blockToRST tabStop HorizontalRule = (text "--------------\n", empty)
144−blockToRST tabStop (Header level lst) =
145− let (headerText, refs) = inlineListToRST lst in
146− let headerLength = length $ render headerText in
147− let headerChar = if (level > 5) then ' ' else "=-~^'" !! (level - 1) in
148− let border = text $ replicate headerLength headerChar in
149− (headerText <> char '\n' <> border <> char '\n', refs)
150−blockToRST tabStop (Table caption _ _ headers rows) =
151− blockToRST tabStop (Para [Str "pandoc: TABLE unsupported in RST writer"])
152−
153−
154−-- | Convert bullet list item (list of blocks) to reStructuredText.
155−-- Returns a pair of 'Doc', the first the main text, the second references
156−bulletListItemToRST :: Int -- ^ tab stop
157− -> [Block] -- ^ list item (list of blocks)
158− -> (Doc, Doc)
159−bulletListItemToRST tabStop list =
160− let (main, refs) = unzip $ map (blockToRST tabStop) list in
161− (hang (text "- ") tabStop (vcat main), (vcat refs))
162−
163−-- | Convert an ordered list item (list of blocks) to reStructuredText.
164−-- Returns a pair of 'Doc', the first the main text, the second references
165−orderedListItemToRST :: Int -- ^ tab stop
166− -> Int -- ^ ordinal number of list item
167− -> [Block] -- ^ list item (list of blocks)
168− -> (Doc, Doc)
169−orderedListItemToRST tabStop num list =
170− let (main, refs) = unzip $ map (blockToRST tabStop) list
171− spacer = if (length (show num) < 2) then " " else "" in
172− (hang (text ((show num) ++ "." ++ spacer)) tabStop (vcat main), (vcat refs))
173−
174−-- | Convert a list of inline elements to reStructuredText.
175−-- Returns a pair of 'Doc', the first the main text, the second references.
176−inlineListToRST :: [Inline] -> (Doc, Doc)
177−inlineListToRST lst = let (main, refs) = unzip $ map inlineToRST lst in
178− (hcat main, hcat refs)
179−
180−-- | Convert an inline element to reStructuredText.
181−-- Returns a pair of 'Doc', the first the main text, the second references.
182−inlineToRST :: Inline -> (Doc, Doc) -- second Doc is list of refs for end of file
183−inlineToRST (Emph lst) = let (main, refs) = inlineListToRST lst in
184− (text "*" <> main <> text "*", refs)
185−inlineToRST (Strong lst) = let (main, refs) = inlineListToRST lst in
186− (text "**" <> main <> text "**", refs)
187−inlineToRST (Quoted SingleQuote lst) = let (main, refs) = inlineListToRST lst in
188− (char '\'' <> main <> char '\'', refs)
189−inlineToRST (Quoted DoubleQuote lst) = let (main, refs) = inlineListToRST lst in
190− (char '"' <> main <> char '"', refs)
191−inlineToRST EmDash = (text "--", empty)
192−inlineToRST EnDash = (char '-', empty)
193−inlineToRST Apostrophe = (char '\'', empty)
194−inlineToRST Ellipses = (text "...", empty)
195−inlineToRST (Code str) = (text $ "``" ++ str ++ "``", empty)
196−inlineToRST (Str str) = (text $ escapeString str, empty)
197−inlineToRST (TeX str) = (text str, empty)
198−inlineToRST (HtmlInline str) = (empty, empty)
199−inlineToRST (LineBreak) = inlineToRST Space -- RST doesn't have line breaks
200−inlineToRST Space = (char ' ', empty)
201−--
202−-- Note: can assume reference links have been replaced where possible
203−-- with explicit links.
204−--
205−inlineToRST (Link txt (Src src tit)) =
206− let (linktext, ref') = if (null txt) || (txt == [Str ""])
207− then (text "link", empty)
208− else inlineListToRST $ normalizeSpaces txt in
209− let link = char '`' <> linktext <> text "`_"
210− linktext' = render linktext in
211− let linktext'' = if (':' `elem` linktext')
212− then "`" ++ linktext' ++ "`"
213− else linktext' in
214− let ref = text ".. _" <> text linktext'' <> text ": " <> text src in
215− (link, ref' $$ ref)
216−inlineToRST (Link txt (Ref ref)) =
217− let (linktext, refs1) = inlineListToRST txt
218− (reftext, refs2) = inlineListToRST ref in
219− (char '[' <> linktext <> text "][" <> reftext <> char ']', refs1 $$ refs2)
220−inlineToRST (Image alternate (Src source tit)) =
221− let (alt, ref') = if (null alternate) || (alternate == [Str ""])
222− then (text "image", empty)
223− else inlineListToRST $ normalizeSpaces alternate in
224− let link = char '|' <> alt <> char '|' in
225− let ref = text ".. " <> link <> text " image:: " <> text source in
226− (link, ref' $$ ref)
227−-- The following case won't normally occur...
228−inlineToRST (Image alternate (Ref ref)) =
229− let (alttext, refs1) = inlineListToRST alternate
230− (reftext, refs2) = inlineListToRST ref in
231− (char '|' <> alttext <> char '|', refs1 $$ refs2)
232−inlineToRST (NoteRef ref) =
233− (text " [" <> text (escapeString ref) <> char ']' <> char '_', empty)
166+ return $ hang (text "\n.. raw:: html\n") 3 (vcat $ map text (lines str'))
167+blockToRST opts HorizontalRule = return $ text "--------------\n"
168+blockToRST opts (Header level inlines) = do
169+ contents <- inlineListToRST opts inlines
170+ let headerLength = length $ render contents
171+ let headerChar = if (level > 5) then ' ' else "=-~^'" !! (level - 1)
172+ let border = text $ replicate headerLength headerChar
173+ return $ contents <> char '\n' <> border <> char '\n'
174+blockToRST opts (CodeBlock str) = return $ (text "::\n") $$ text "" $$
175+ (nest (writerTabStop opts) $ vcat $ map text (lines str)) <> text "\n"
176+blockToRST opts (BlockQuote blocks) = do
177+ contents <- blockListToRST opts blocks
178+ return $ (nest (writerTabStop opts) contents) <> text "\n"
179+blockToRST opts (Table caption _ _ headers rows) = blockToRST opts
180+ (Para [Str "pandoc: TABLE unsupported in RST writer"])
181+blockToRST opts (BulletList items) = do
182+ contents <- mapM (bulletListItemToRST opts) items
183+ return $ (vcat contents) <> text "\n"
184+blockToRST opts (OrderedList items) = do
185+ contents <- mapM (\(item, num) -> orderedListItemToRST opts item num) $
186+ zip [1..] items
187+ return $ (vcat contents) <> text "\n"
188+
189+-- | Convert bullet list item (list of blocks) to RST.
190+bulletListItemToRST :: WriterOptions -> [Block] -> State WriterState Doc
191+bulletListItemToRST opts items = do
192+ contents <- blockListToRST opts items
193+ return $ hang (text "- ") (writerTabStop opts) contents
194+
195+-- | Convert ordered list item (a list of blocks) to RST.
196+orderedListItemToRST :: WriterOptions -- ^ options
197+ -> Int -- ^ ordinal number of list item
198+ -> [Block] -- ^ list item (list of blocks)
199+ -> State WriterState Doc
200+orderedListItemToRST opts num items = do
201+ contents <- blockListToRST opts items
202+ let spacer = if (num < 10) then " " else ""
203+ return $ hang (text ((show num) ++ "." ++ spacer)) (writerTabStop opts)
204+ contents
205+
206+-- | Convert list of Pandoc block elements to RST.
207+blockListToRST :: WriterOptions -- ^ Options
208+ -> [Block] -- ^ List of block elements
209+ -> State WriterState Doc
210+blockListToRST opts blocks =
211+ mapM (blockToRST opts) blocks >>= (return . vcat)
212+
213+-- | Convert list of Pandoc inline elements to RST.
214+inlineListToRST :: WriterOptions -> [Inline] -> State WriterState Doc
215+inlineListToRST opts lst = mapM (inlineToRST opts) lst >>= (return . hcat)
216+
217+-- | Convert Pandoc inline element to RST.
218+inlineToRST :: WriterOptions -> Inline -> State WriterState Doc
219+inlineToRST opts (Emph lst) = do
220+ contents <- inlineListToRST opts lst
221+ return $ text "*" <> contents <> text "*"
222+inlineToRST opts (Strong lst) = do
223+ contents <- inlineListToRST opts lst
224+ return $ text "**" <> contents <> text "**"
225+inlineToRST opts (Quoted SingleQuote lst) = do
226+ contents <- inlineListToRST opts lst
227+ return $ char '\'' <> contents <> char '\''
228+inlineToRST opts (Quoted DoubleQuote lst) = do
229+ contents <- inlineListToRST opts lst
230+ return $ char '"' <> contents <> char '"'
231+inlineToRST opts EmDash = return $ text "--"
232+inlineToRST opts EnDash = return $ char '-'
233+inlineToRST opts Apostrophe = return $ char '\''
234+inlineToRST opts Ellipses = return $ text "..."
235+inlineToRST opts (Code str) = return $ text $ "``" ++ str ++ "``"
236+inlineToRST opts (Str str) = return $ text $ escapeString str
237+inlineToRST opts (TeX str) = return $ text str
238+inlineToRST opts (HtmlInline str) = return empty
239+inlineToRST opts (LineBreak) = return $ text " " -- RST doesn't have linebreaks
240+inlineToRST opts Space = return $ char ' '
241+inlineToRST opts (Link txt (src, tit)) = do
242+ let useReferenceLinks = writerReferenceLinks opts
243+ let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
244+ let useAuto = null tit && txt == [Str srcSuffix]
245+ (notes, refs, pics) <- get
246+ linktext <- inlineListToRST opts $ normalizeSpaces txt
247+ link <- if useReferenceLinks
248+ then do let refs' = if (txt, (src, tit)) `elem` refs
249+ then refs
250+ else (txt, (src, tit)):refs
251+ put (notes, refs', pics)
252+ return $ char '`' <> linktext <> text "`_"
253+ else return $ char '`' <> linktext <> text " <" <>
254+ text src <> text ">`_"
255+ return link
256+inlineToRST opts (Image alternate (source, tit)) = do
257+ (notes, refs, pics) <- get
258+ let labelsUsed = map fst pics
259+ let txt = if (null alternate) || (alternate == [Str ""]) ||
260+ (alternate `elem` labelsUsed)
261+ then [Str $ "image" ++ show (length refs)]
262+ else alternate
263+ let pics' = if (txt, (source, tit)) `elem` pics
264+ then pics
265+ else (txt, (source, tit)):pics
266+ put (notes, refs, pics')
267+ label <- inlineListToRST opts txt
268+ return $ char '|' <> label <> char '|'
269+inlineToRST opts (Note contents) = do
270+ -- add to notes in state
271+ modify (\(notes, refs, pics) -> (contents:notes, refs, pics))
272+ (notes, _, _) <- get
273+ let ref = show $ (length notes)
274+ return $ text " [" <> text ref <> text "]_"
src/Text/Pandoc/Writers/RTF.hs+58−79
@@ -17,7 +17,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1717-}
1818
1919{- |
20− Module :
20+ Module : Text.Pandoc.Writers.RTF
2121 Copyright : Copyright (C) 2006 John MacFarlane
2222 License : GNU GPL, version 2 or above
2323
@@ -27,26 +27,21 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2727
2828Conversion of 'Pandoc' documents to RTF (rich text format).
2929-}
30−module Text.Pandoc.Writers.RTF (
31− writeRTF
32− ) where
30+module Text.Pandoc.Writers.RTF ( writeRTF) where
3331import Text.Pandoc.Definition
3432import Text.Pandoc.Shared
3533import Text.Regex ( matchRegexAll, mkRegex )
36−import List ( isSuffixOf )
37−import Char ( ord, chr )
34+import Data.List ( isSuffixOf )
35+import Data.Char ( ord, chr )
3836
3937-- | Convert Pandoc to a string in rich text format.
4038writeRTF :: WriterOptions -> Pandoc -> String
4139writeRTF options (Pandoc meta blocks) =
42− -- assumes all notes are at outer level
43− let notes = filter isNoteBlock blocks in
4440 let head = if writerStandalone options
45− then rtfHeader notes (writerHeader options) meta
41+ then rtfHeader (writerHeader options) meta
4642 else ""
4743 foot = if writerStandalone options then "\n}\n" else ""
48− body = (writerIncludeBefore options) ++ (concatMap (blockToRTF notes 0)
49− (replaceReferenceLinks blocks)) ++
44+ body = (writerIncludeBefore options) ++ concatMap (blockToRTF 0) blocks ++
5045 (writerIncludeAfter options) in
5146 head ++ body ++ foot
5247
@@ -120,15 +115,14 @@ orderedMarkers indent =
120115 otherwise -> map (\x -> show x ++ ".") $ cycle ['a'..'z']
121116
122117-- | Returns RTF header.
123−rtfHeader :: [Block] -- ^ list of note blocks
124− -> String -- ^ header text
118+rtfHeader :: String -- ^ header text
125119 -> Meta -- ^ bibliographic information
126120 -> String
127−rtfHeader notes headerText (Meta title authors date) =
121+rtfHeader headerText (Meta title authors date) =
128122 let titletext = if null title
129123 then ""
130124 else rtfPar 0 0 ("\\qc \\b \\fs36 " ++
131− inlineListToRTF notes title)
125+ inlineListToRTF title)
132126 authorstext = if null authors
133127 then ""
134128 else rtfPar 0 0 ("\\qc " ++ (joinWithSep "\\"
@@ -142,35 +136,32 @@ rtfHeader notes headerText (Meta title authors date) =
142136 headerText ++ titletext ++ authorstext ++ datetext ++ spacer
143137
144138-- | Convert Pandoc block element to RTF.
145−blockToRTF :: [Block] -- ^ list of note blocks
146− -> Int -- ^ indent level
139+blockToRTF :: Int -- ^ indent level
147140 -> Block -- ^ block to convert
148141 -> String
149−blockToRTF notes indent Null = ""
150−blockToRTF notes indent (Plain lst) =
151− rtfCompact indent 0 (inlineListToRTF notes lst)
152−blockToRTF notes indent (Para lst) =
153− rtfPar indent 0 (inlineListToRTF notes lst)
154−blockToRTF notes indent (BlockQuote lst) =
155− concatMap (blockToRTF notes (indent + indentIncrement)) lst
156−blockToRTF notes indent (Note ref lst) = "" -- shouldn't be any aftr filtering
157−blockToRTF notes indent (Key _ _) = ""
158−blockToRTF notes indent (CodeBlock str) =
142+blockToRTF indent Null = ""
143+blockToRTF indent (Plain lst) =
144+ rtfCompact indent 0 (inlineListToRTF lst)
145+blockToRTF indent (Para lst) =
146+ rtfPar indent 0 (inlineListToRTF lst)
147+blockToRTF indent (BlockQuote lst) =
148+ concatMap (blockToRTF (indent + indentIncrement)) lst
149+blockToRTF indent (CodeBlock str) =
159150 rtfPar indent 0 ("\\f1 " ++ (codeStringToRTF str))
160−blockToRTF notes indent (RawHtml str) = ""
161−blockToRTF notes indent (BulletList lst) =
151+blockToRTF indent (RawHtml str) = ""
152+blockToRTF indent (BulletList lst) =
162153 spaceAtEnd $
163− concatMap (listItemToRTF notes indent (bulletMarker indent)) lst
164−blockToRTF notes indent (OrderedList lst) =
154+ concatMap (listItemToRTF indent (bulletMarker indent)) lst
155+blockToRTF indent (OrderedList lst) =
165156 spaceAtEnd $ concat $
166− zipWith (listItemToRTF notes indent) (orderedMarkers indent) lst
167−blockToRTF notes indent HorizontalRule =
157+ zipWith (listItemToRTF indent) (orderedMarkers indent) lst
158+blockToRTF indent HorizontalRule =
168159 rtfPar indent 0 "\\qc \\emdash\\emdash\\emdash\\emdash\\emdash"
169−blockToRTF notes indent (Header level lst) =
160+blockToRTF indent (Header level lst) =
170161 rtfPar indent 0 ("\\b \\fs" ++ (show (40 - (level * 4))) ++ " " ++
171− (inlineListToRTF notes lst))
172−blockToRTF notes indent (Table caption _ _ headers rows) =
173− blockToRTF notes indent (Para [Str "pandoc: TABLE unsupported in RST writer"])
162+ (inlineListToRTF lst))
163+blockToRTF indent (Table caption _ _ headers rows) =
164+ blockToRTF indent (Para [Str "pandoc: TABLE unsupported in RST writer"])
174165
175166-- | Ensure that there's the same amount of space after compact
176167-- lists as after regular lists.
@@ -181,16 +172,15 @@ spaceAtEnd str =
181172 else str
182173
183174-- | Convert list item (list of blocks) to RTF.
184−listItemToRTF :: [Block] -- ^ list of note blocks
185− -> Int -- ^ indent level
175+listItemToRTF :: Int -- ^ indent level
186176 -> String -- ^ list start marker
187177 -> [Block] -- ^ list item (list of blocks)
188178 -> [Char]
189−listItemToRTF notes indent marker [] =
179+listItemToRTF indent marker [] =
190180 rtfCompact (indent + listIncrement) (0 - listIncrement)
191181 (marker ++ "\\tx" ++ (show listIncrement) ++ "\\tab ")
192−listItemToRTF notes indent marker list =
193− let (first:rest) = map (blockToRTF notes (indent + listIncrement)) list in
182+listItemToRTF indent marker list =
183+ let (first:rest) = map (blockToRTF (indent + listIncrement)) list in
194184 -- insert the list marker into the (processed) first block
195185 let modFirst = case matchRegexAll (mkRegex "\\\\fi-?[0-9]+") first of
196186 Just (before, matched, after, _) -> before ++ "\\fi" ++
@@ -200,47 +190,36 @@ listItemToRTF notes indent marker list =
200190 modFirst ++ (concat rest)
201191
202192-- | Convert list of inline items to RTF.
203−inlineListToRTF :: [Block] -- ^ list of note blocks
204− -> [Inline] -- ^ list of inlines to convert
193+inlineListToRTF :: [Inline] -- ^ list of inlines to convert
205194 -> String
206−inlineListToRTF notes lst = concatMap (inlineToRTF notes) lst
195+inlineListToRTF lst = concatMap inlineToRTF lst
207196
208197-- | Convert inline item to RTF.
209−inlineToRTF :: [Block] -- ^ list of note blocks
210− -> Inline -- ^ inline to convert
198+inlineToRTF :: Inline -- ^ inline to convert
211199 -> String
212−inlineToRTF notes (Emph lst) = "{\\i " ++ (inlineListToRTF notes lst) ++ "} "
213−inlineToRTF notes (Strong lst) =
214− "{\\b " ++ (inlineListToRTF notes lst) ++ "} "
215−inlineToRTF notes (Quoted SingleQuote lst) =
216− "\\u8216'" ++ (inlineListToRTF notes lst) ++ "\\u8217'"
217−inlineToRTF notes (Quoted DoubleQuote lst) =
218− "\\u8220\"" ++ (inlineListToRTF notes lst) ++ "\\u8221\""
219−inlineToRTF notes Apostrophe = "\\u8217'"
220−inlineToRTF notes Ellipses = "\\u8230?"
221−inlineToRTF notes EmDash = "\\u8212-"
222−inlineToRTF notes EnDash = "\\u8211-"
223−inlineToRTF notes (Code str) = "{\\f1 " ++ (codeStringToRTF str) ++ "} "
224−inlineToRTF notes (Str str) = stringToRTF str
225−inlineToRTF notes (TeX str) = latexToRTF str
226−inlineToRTF notes (HtmlInline str) = ""
227−inlineToRTF notes (LineBreak) = "\\line "
228−inlineToRTF notes Space = " "
229−inlineToRTF notes (Link text (Src src tit)) =
200+inlineToRTF (Emph lst) = "{\\i " ++ (inlineListToRTF lst) ++ "} "
201+inlineToRTF (Strong lst) =
202+ "{\\b " ++ (inlineListToRTF lst) ++ "} "
203+inlineToRTF (Quoted SingleQuote lst) =
204+ "\\u8216'" ++ (inlineListToRTF lst) ++ "\\u8217'"
205+inlineToRTF (Quoted DoubleQuote lst) =
206+ "\\u8220\"" ++ (inlineListToRTF lst) ++ "\\u8221\""
207+inlineToRTF Apostrophe = "\\u8217'"
208+inlineToRTF Ellipses = "\\u8230?"
209+inlineToRTF EmDash = "\\u8212-"
210+inlineToRTF EnDash = "\\u8211-"
211+inlineToRTF (Code str) = "{\\f1 " ++ (codeStringToRTF str) ++ "} "
212+inlineToRTF (Str str) = stringToRTF str
213+inlineToRTF (TeX str) = latexToRTF str
214+inlineToRTF (HtmlInline str) = ""
215+inlineToRTF (LineBreak) = "\\line "
216+inlineToRTF Space = " "
217+inlineToRTF (Link text (src, tit)) =
230218 "{\\field{\\*\\fldinst{HYPERLINK \"" ++ (codeStringToRTF src) ++
231− "\"}}{\\fldrslt{\\ul\n" ++ (inlineListToRTF notes text) ++ "\n}}}\n"
232−inlineToRTF notes (Link text (Ref ref)) =
233− "[" ++ (inlineListToRTF notes text) ++ "][" ++
234− (inlineListToRTF notes ref) ++ "]" -- this is what markdown does
235−inlineToRTF notes (Image alternate (Src source tit)) =
219+ "\"}}{\\fldrslt{\\ul\n" ++ (inlineListToRTF text) ++ "\n}}}\n"
220+inlineToRTF (Image alternate (source, tit)) =
236221 "{\\cf1 [image: " ++ source ++ "]\\cf0}"
237−inlineToRTF notes (Image alternate (Ref ref)) = "![" ++
238− (inlineListToRTF notes alternate) ++ "][" ++
239− (inlineListToRTF notes ref) ++ "]"
240−inlineToRTF [] (NoteRef ref) = ""
241−inlineToRTF ((Note firstref firstblocks):rest) (NoteRef ref) =
242− if firstref == ref
243− then "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
244− (concatMap (blockToRTF rest 0) firstblocks) ++ "}"
245− else inlineToRTF rest (NoteRef ref)
222+inlineToRTF (Note contents) =
223+ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
224+ (concatMap (blockToRTF 0) contents) ++ "}"
246225
src/Text/ParserCombinators/Pandoc.hs+10−2
@@ -40,12 +40,13 @@ module Text.ParserCombinators.Pandoc (
4040 enclosed,
4141 nullBlock,
4242 stringAnyCase,
43− parseFromStr
43+ parseFromStr,
44+ lineClump
4445 ) where
4546import Text.ParserCombinators.Parsec
4647import Text.Pandoc.Definition
4748import Text.Pandoc.Shared
48−import Char ( toUpper, toLower )
49+import Data.Char ( toUpper, toLower )
4950
5051--- | Parse any line of text
5152anyLine :: GenParser Char st [Char]
@@ -132,4 +133,11 @@ parseFromStr parser str = try $ do
132133 setInput oldInput
133134 return result
134135
136+-- | Parse raw line block up to and including blank lines.
137+lineClump :: GenParser Char st String
138+lineClump = do
139+ lines <- many1 (do{notFollowedBy blankline; anyLine})
140+ blanks <- blanklines <|> (do{eof; return "\n"})
141+ return ((unlines lines) ++ blanks)
142+
135143
tests/html-reader.native+33−53
@@ -2,7 +2,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] [] "")
22[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
33, HorizontalRule
44, Header 1 [Str "Headers"]
5−, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] (Ref [Str "1"])]
5+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
66, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
77, Header 4 [Str "Level",Space,Str "4"]
88, Header 5 [Str "Level",Space,Str "5"]
@@ -187,7 +187,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] [] "")
187187, Header 1 [Str "Inline",Space,Str "Markup"]
188188, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
189189, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
190−, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] (Ref [Str "1"])],Str "."]
190+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
191191, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
192192, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
193193, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
@@ -199,7 +199,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] [] "")
199199, Para [Str "'A',",Space,Str "'B',",Space,Str "and",Space,Str "'C'",Space,Str "are",Space,Str "letters."]
200200, Para [Str "'Oak,'",Space,Str "'elm,'",Space,Str "and",Space,Str "'beech'",Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Str "'pine.'"]
201201, Para [Str "'He",Space,Str "said,",Space,Str "\"I",Space,Str "want",Space,Str "to",Space,Str "go.\"'",Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70's?"]
202−, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code "code",Str "'",Space,Str "and",Space,Str "a",Space,Str "\"",Link [Str "quoted",Space,Str "link"] (Ref [Str "2"]),Str "\"."]
202+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Str "'",Code "code",Str "'",Space,Str "and",Space,Str "a",Space,Str "\"",Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2",""),Str "\"."]
203203, Para [Str "Some",Space,Str "dashes:",Space,Str "one---two",Space,Str "---",Space,Str "three--four",Space,Str "--",Space,Str "five."]
204204, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5-7,",Space,Str "255-66,",Space,Str "1987-1999."]
205205, Para [Str "Ellipses...and.",Space,Str ".",Space,Str ".and",Space,Str ".",Space,Str ".",Space,Str ".",Space,Str "."]
@@ -255,74 +255,54 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] [] "")
255255, HorizontalRule
256256, Header 1 [Str "Links"]
257257, Header 2 [Str "Explicit"]
258−, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] (Ref [Str "3"]),Str "."]
259−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Ref [Str "4"]),Str "."]
260−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Ref [Str "5"]),Str "."]
261−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Ref [Str "6"]),Str "."]
262−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Ref [Str "7"])]
263−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Ref [Str "8"])]
258+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
259+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
260+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
261+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
262+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
263+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
264264, Plain [Str "Email",Space,Str "link",Space,Str "(nobody",Space,Str "[at]",Space,Str "nowhere.net)"]
265−, Para [Link [Str "Empty"] (Ref [Str "9"]),Str "."]
265+, Para [Link [Str "Empty"] ("",""),Str "."]
266266, Header 2 [Str "Reference"]
267−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "3"]),Str "."]
268−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "3"]),Str "."]
269−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "3"]),Str "."]
270−, Para [Str "With",Space,Link [Str "embedded",Space,Str "[brackets]"] (Ref [Str "3"]),Str "."]
271−, Para [Link [Str "b"] (Ref [Str "3"]),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
272−, Para [Str "Indented",Space,Link [Str "once"] (Ref [Str "1"]),Str "."]
273−, Para [Str "Indented",Space,Link [Str "twice"] (Ref [Str "1"]),Str "."]
274−, Para [Str "Indented",Space,Link [Str "thrice"] (Ref [Str "1"]),Str "."]
267+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
268+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
269+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
270+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
271+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
272+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
273+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
274+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
275275, Para [Str "This",Space,Str "should",Space,Str "[not]",Space,Str "be",Space,Str "a",Space,Str "link."]
276276, CodeBlock "[not]: /url"
277−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "10"]),Str "."]
278−, Para [Str "Foo",Space,Link [Str "biz"] (Ref [Str "11"]),Str "."]
277+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
278+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
279279, Header 2 [Str "With",Space,Str "ampersands"]
280−, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] (Ref [Str "2"]),Str "."]
281−, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] (Ref [Str "12"]),Str "."]
282−, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] (Ref [Str "13"]),Str "."]
283−, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] (Ref [Str "13"]),Str "."]
280+, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
281+, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
282+, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
283+, Para [Str "Here's",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
284284, Header 2 [Str "Autolinks"]
285−, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1",Str "&",Str "bar=2"] (Ref [Str "2"])]
285+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1",Str "&",Str "bar=2"] ("http://example.com/?foo=1&bar=2","")]
286286, BulletList
287287 [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
288− , [ Plain [Link [Str "http://example.com/"] (Ref [Str "14"])] ]
288+ , [ Plain [Link [Str "http://example.com/"] ("http://example.com/","")] ]
289289 , [ Plain [Str "It",Space,Str "should."] ] ]
290290, Plain [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Str "nobody",Space,Str "[at]",Space,Str "nowhere.net"]
291291, BlockQuote
292− [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] (Ref [Str "14"])] ]
292+ [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] ("http://example.com/","")] ]
293293
294294, Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
295295, CodeBlock "or here: <http://example.com/>"
296296, HorizontalRule
297297, Header 1 [Str "Images"]
298298, Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
299−, Para [Image [Str "lalune"] (Ref [Str "15"])]
300−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] (Ref [Str "16"]),Space,Str "icon."]
299+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
300+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon."]
301301, HorizontalRule
302302, Header 1 [Str "Footnotes"]
303−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link [Str "(1)"] (Ref [Str "17"]),Str ",",Space,Str "and",Space,Str "another",Link [Str "(longnote)"] (Ref [Str "18"]),Str ".",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
304−, Para [Link [Str "(1)"] (Ref [Str "19"]),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
305−, Para [Link [Str "(longnote)"] (Ref [Str "20"]),Space,Str "Here's",Space,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
303+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference",Link [Str "(1)"] ("#note_1",""),Str ",",Space,Str "and",Space,Str "another",Link [Str "(longnote)"] ("#note_longnote",""),Str ".",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space^(my",Space,Str "note)."]
304+, Para [Link [Str "(1)"] ("#ref_1",""),Space,Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "in",Space,Str "the",Space,Str "document,",Space,Str "not",Space,Str "just",Space,Str "at",Space,Str "the",Space,Str "end."]
305+, Para [Link [Str "(longnote)"] ("#ref_longnote",""),Space,Str "Here's",Space,Str "the",Space,Str "other",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."]
306306, Para [Str "Caret",Space,Str "characters",Space,Str "are",Space,Str "used",Space,Str "to",Space,Str "indicate",Space,Str "that",Space,Str "the",Space,Str "blocks",Space,Str "all",Space,Str "belong",Space,Str "to",Space,Str "a",Space,Str "single",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "block",Space,Str "quotes)."]
307307, CodeBlock " { <code> }"
308−, Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",Space,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."]
309−, Key [Str "1"] (Src "/url" "")
310−, Key [Str "2"] (Src "http://example.com/?foo=1&bar=2" "")
311−, Key [Str "3"] (Src "/url/" "")
312−, Key [Str "4"] (Src "/url/" "title")
313−, Key [Str "5"] (Src "/url/" "title preceded by two spaces")
314−, Key [Str "6"] (Src "/url/" "title preceded by a tab")
315−, Key [Str "7"] (Src "/url/" "title with \"quotes\" in it")
316−, Key [Str "8"] (Src "/url/" "title with single quotes")
317−, Key [Str "9"] (Src "" "")
318−, Key [Str "10"] (Src "/url/" "Title with \"quotes\" inside")
319−, Key [Str "11"] (Src "/url/" "Title with \"quote\" inside")
320−, Key [Str "12"] (Src "http://att.com/" "AT&T")
321−, Key [Str "13"] (Src "/script?foo=1&bar=2" "")
322−, Key [Str "14"] (Src "http://example.com/" "")
323−, Key [Str "15"] (Src "lalune.jpg" "Voyage dans la Lune")
324−, Key [Str "16"] (Src "movie.jpg" "")
325−, Key [Str "17"] (Src "#note_1" "")
326−, Key [Str "18"] (Src "#note_longnote" "")
327−, Key [Str "19"] (Src "#ref_1" "")
328−, Key [Str "20"] (Src "#ref_longnote" "") ]
308+, Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "use",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "every",Space,Str "line,",Space,Str "as",Space,Str "with",Space,Str "blockquotes,",Space,Str "but",Space,Str "all",Space,Str "that",Space,Str "you",Space,Str "need",Space,Str "is",Space,Str "a",Space,Str "caret",Space,Str "at",Space,Str "the",Space,Str "beginning",Space,Str "of",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "the",Space,Str "block",Space,Str "and",Space,Str "any",Space,Str "preceding",Space,Str "blank",Space,Str "lines."] ]
tests/rst-reader.native+8−14
@@ -156,21 +156,15 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":",Space,Str
156156, Para [Str "Plus",Str ":",Space,Str "+"]
157157, Para [Str "Minus",Str ":",Space,Str "-"]
158158, Header 1 [Str "Links"]
159−, Para [Str "Explicit",Str ":",Space,Str "a",Space,Link [Str "URL"] (Src "/url/" ""),Str "."]
160−, Para [Str "Two",Space,Str "anonymous",Space,Str "links",Str ":",Space,Link [Str "the",Space,Str "first"] (Src "/url1/" ""),Space,Str "and",Space,Link [Str "the",Space,Str "second"] (Src "/url2/" "")]
161−, Para [Str "Reference",Space,Str "links",Str ":",Space,Link [Str "link1"] (Ref []),Space,Str "and",Space,Link [Str "link2"] (Ref []),Space,Str "and",Space,Link [Str "link1"] (Ref []),Space,Str "again."]
162−, Key [Str "link1"] (Src "/url1/" "")
163−, Key [Str "link2"] (Src "/url2/" "")
164−, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] (Ref []),Str "."]
165−, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text",Str ":",Space,Link [Str "AT&T"] (Src "/url/" ""),Str "."]
166−, Key [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] (Src "http://example.com/?foo=1&bar=2" "")
167−, Para [Str "Autolinks",Str ":",Space,Link [Str "http://example.com/?foo=1&bar=2"] (Src "http://example.com/?foo=1&bar=2" ""),Space,Str "and",Space,Link [Str "nobody@nowhere.net"] (Src "mailto:nobody@nowhere.net" ""),Str "."]
159+, Para [Str "Explicit",Str ":",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
160+, Para [Str "Two",Space,Str "anonymous",Space,Str "links",Str ":",Space,Link [Str "the",Space,Str "first"] ("/url1/",""),Space,Str "and",Space,Link [Str "the",Space,Str "second"] ("/url2/","")]
161+, Para [Str "Reference",Space,Str "links",Str ":",Space,Link [Str "link1"] ("/url1/",""),Space,Str "and",Space,Link [Str "link2"] ("/url2/",""),Space,Str "and",Space,Link [Str "link1"] ("/url1/",""),Space,Str "again."]
162+, Para [Str "Here's",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
163+, Para [Str "Here's",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text",Str ":",Space,Link [Str "AT&T"] ("/url/",""),Str "."]
164+, Para [Str "Autolinks",Str ":",Space,Link [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2",""),Space,Str "and",Space,Link [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net",""),Str "."]
168165, Para [Str "But",Space,Str "not",Space,Str "here",Str ":"]
169166, CodeBlock "http://example.com/"
170167, Header 1 [Str "Images"]
171168, Para [Str "From",Space,Str "\"Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune\"",Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902)",Str ":"]
172−, Plain [Image [Str "image"] (Src "lalune.jpg" "")]
173−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] (Ref [Str "movie"]),Space,Str "icon."]
174−, Key [Str "movie"] (Src "movie.jpg" "")
175−, Null
176−, Plain [] ]
169+, Plain [Image [Str "image"] ("lalune.jpg","")]
170+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon."] ]
tests/testsuite.native+36−62
@@ -2,7 +2,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
22[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Str ".",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite",Str "."]
33, HorizontalRule
44, Header 1 [Str "Headers"]
5−, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] (Src "/url" "")]
5+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
66, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
77, Header 4 [Str "Level",Space,Str "4"]
88, Header 5 [Str "Level",Space,Str "5"]
@@ -196,7 +196,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
196196, Header 1 [Str "Inline",Space,Str "Markup"]
197197, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
198198, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
199−, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] (Src "/url" "")],Str "."]
199+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
200200, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
201201, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
202202, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
@@ -208,7 +208,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
208208, Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters",Str "."]
209209, Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees",Str ".",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine",Str "."]]
210210, Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go",Str "."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70",Apostrophe,Str "s?"]
211−, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] (Ref [Str "1"])],Str "."]
211+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
212212, Para [Str "Some",Space,Str "dashes:",Space,Str "one",EmDash,Str "two",EmDash,Str "three",EmDash,Str "four",EmDash,Str "five",Str "."]
213213, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5",EnDash,Str "7,",Space,Str "255",EnDash,Str "66,",Space,Str "1987",EnDash,Str "1999",Str "."]
214214, Para [Str "Ellipses",Ellipses,Str "and",Ellipses,Str "and",Ellipses,Str "."]
@@ -264,83 +264,57 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
264264, HorizontalRule
265265, Header 1 [Str "Links"]
266266, Header 2 [Str "Explicit"]
267−, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] (Src "/url/" ""),Str "."]
268−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title"),Str "."]
269−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title preceded by two spaces"),Str "."]
270−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title preceded by a tab"),Str "."]
271−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title with \"quotes\" in it")]
272−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title with single quotes")]
273−, Para [Link [Str "with",Str "_",Str "underscore"] (Src "/url/with_underscore" "")]
274−, Para [Link [Str "Email",Space,Str "link"] (Src "mailto:nobody@nowhere.net" "")]
275−, Para [Link [Str "Empty"] (Src "" ""),Str "."]
267+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
268+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
269+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
270+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
271+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
272+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
273+, Para [Link [Str "with",Str "_",Str "underscore"] ("/url/with_underscore","")]
274+, Para [Link [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
275+, Para [Link [Str "Empty"] ("",""),Str "."]
276276, Header 2 [Str "Reference"]
277−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
278−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
279−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
280−, Key [Str "a"] (Src "/url/" "")
281−, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] (Ref [Str "b"]),Str "."]
282−, Para [Link [Str "b"] (Ref [Str "b"]),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
283−, Para [Str "Indented",Space,Link [Str "once"] (Ref [Str "once"]),Str "."]
284−, Para [Str "Indented",Space,Link [Str "twice"] (Ref [Str "twice"]),Str "."]
285−, Para [Str "Indented",Space,Link [Str "thrice"] (Ref [Str "thrice"]),Str "."]
277+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
278+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
279+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
280+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] ("/url/",""),Str "."]
281+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
282+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
283+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
284+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
286285, Para [Str "This",Space,Str "should",Space,Str "[",Str "not",Str "]",Str "[",Str "]",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
287−, Key [Str "once"] (Src "/url" "")
288−, Key [Str "twice"] (Src "/url" "")
289−, Key [Str "thrice"] (Src "/url" "")
290286, CodeBlock "[not]: /url"
291−, Key [Str "b"] (Src "/url/" "")
292−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "bar"]),Str "."]
293−, Para [Str "Foo",Space,Link [Str "biz"] (Src "/url/" "Title with \"quote\" inside"),Str "."]
294−, Key [Str "bar"] (Src "/url/" "Title with \"quotes\" inside")
287+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
288+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
295289, Header 2 [Str "With",Space,Str "ampersands"]
296−, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] (Ref [Str "1"]),Str "."]
297−, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] (Ref [Str "2"]),Str "."]
298−, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] (Src "/script?foo=1&bar=2" ""),Str "."]
299−, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] (Src "/script?foo=1&bar=2" ""),Str "."]
300−, Key [Str "1"] (Src "http://example.com/?foo=1&bar=2" "")
301−, Key [Str "2"] (Src "http://att.com/" "AT&T")
290+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
291+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
292+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
293+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
302294, Header 2 [Str "Autolinks"]
303−, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1&bar=2"] (Src "http://example.com/?foo=1&bar=2" "")]
295+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
304296, BulletList
305297 [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
306− , [ Plain [Link [Str "http://example.com/"] (Src "http://example.com/" "")] ]
298+ , [ Plain [Link [Str "http://example.com/"] ("http://example.com/","")] ]
307299 , [ Plain [Str "It",Space,Str "should",Str "."] ] ]
308−, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Str "nobody@nowhere.net"] (Src "mailto:nobody@nowhere.net" "")]
300+, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
309301, BlockQuote
310− [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] (Src "http://example.com/" "")] ]
302+ [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] ("http://example.com/","")] ]
311303
312304, Para [Str "Auto",Str "-",Str "links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
313305, CodeBlock "or here: <http://example.com/>"
314306, HorizontalRule
315307, Header 1 [Str "Images"]
316308, Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
317−, Para [Image [Str "lalune"] (Ref [Str "lalune"])]
318−, Key [Str "lalune"] (Src "lalune.jpg" "Voyage dans la Lune")
319−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] (Src "movie.jpg" ""),Space,Str "icon",Str "."]
309+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
310+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon",Str "."]
320311, HorizontalRule
321312, Header 1 [Str "Footnotes"]
322−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",NoteRef "1",Space,Str "and",Space,Str "another",Str ".",NoteRef "2",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",NoteRef "3"]
313+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."]],Space,Str "and",Space,Str "another",Str ".",Note [Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."],CodeBlock " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters",Str "."]]]
323314, BlockQuote
324− [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",NoteRef "4"] ]
315+ [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",Note [Para [Str "In",Space,Str "quote",Str "."]]] ]
325316
326317, OrderedList
327− [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",NoteRef "5"] ]
328− ]
329−, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."]
330−, Note "1"
331− [ Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."] ]
332−
333−, Note "2"
334− [ Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."]
335− , Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."]
336− , CodeBlock " { <code> }"
337− , Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."] ]
338−, Note "3"
339− [ Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] (Src "http://google.com" ""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters",Str "."] ]
340−
341−, Note "4"
342− [ Para [Str "In",Space,Str "quote",Str "."] ]
343−
344−, Note "5"
345− [ Para [Str "In",Space,Str "list",Str "."] ]
318+ [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",Note [Para [Str "In",Space,Str "list",Str "."]]] ]
346319 ]
320+, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."] ]
tests/writer.markdown+26−41
@@ -401,7 +401,8 @@ This is code: `>`, `$`, `\`, `\$`, `<html>`.
401401
402402'He said, "I want to go."' Were you alive in the 70's?
403403
404−Here is some quoted '`code`' and a "[quoted link][1]".
404+Here is some quoted '`code`' and a
405+"[quoted link](http://example.com/?foo=1&bar=2)".
405406
406407Some dashes: one--two--three--four--five.
407408
@@ -522,57 +523,42 @@ Just a [URL](/url/).
522523
523524## Reference
524525
525−Foo [bar][a].
526+Foo [bar](/url/).
526527
527−Foo [bar][a].
528+Foo [bar](/url/).
528529
529−Foo [bar][a].
530+Foo [bar](/url/).
530531
532+With [embedded [brackets]](/url/).
531533
532− [a]: /url/
534+[b](/url/) by itself should be a link.
533535
534−With [embedded [brackets]][b].
536+Indented [once](/url).
535537
536−[b][] by itself should be a link.
538+Indented [twice](/url).
537539
538−Indented [once][].
539−
540−Indented [twice][].
541−
542−Indented [thrice][].
540+Indented [thrice](/url).
543541
544542This should [not][] be a link.
545543
546−
547− [once]: /url
548− [twice]: /url
549− [thrice]: /url
550544 [not]: /url
551545
552−
553− [b]: /url/
554−
555−Foo [bar][].
546+Foo [bar](/url/ "Title with "quotes" inside").
556547
557548Foo [biz](/url/ "Title with "quote" inside").
558549
559−
560− [bar]: /url/ "Title with "quotes" inside"
561−
562550## With ampersands
563551
564−Here's a [link with an ampersand in the URL][1].
552+Here's a
553+[link with an ampersand in the URL](http://example.com/?foo=1&bar=2).
565554
566−Here's a link with an amersand in the link text: [AT&T][2].
555+Here's a link with an amersand in the link text:
556+[AT&T](http://att.com/ "AT&T").
567557
568558Here's an [inline link](/script?foo=1&bar=2).
569559
570560Here's an [inline link in pointy braces](/script?foo=1&bar=2).
571561
572−
573− [1]: http://example.com/?foo=1&bar=2
574− [2]: http://att.com/ "AT&T"
575−
576562## Autolinks
577563
578564With an ampersand: <http://example.com/?foo=1&bar=2>
@@ -596,10 +582,7 @@ Auto-links should not occur here: `<http://example.com/>`
596582
597583From "Voyage dans la Lune" by Georges Melies (1902):
598584
599−![lalune][]
600−
601−
602− [lalune]: lalune.jpg "Voyage dans la Lune"
585+![lalune](lalune.jpg "Voyage dans la Lune")
603586
604587Here is a movie ![movie](movie.jpg) icon.
605588
@@ -619,25 +602,27 @@ note] Here is an inline note.[^3]
619602This paragraph should not be part of the note, as it is not
620603indented.
621604
622−[^1]: Here is the footnote. It can go anywhere after the footnote
605+
606+[^1]:
607+ Here is the footnote. It can go anywhere after the footnote
623608 reference. It need not be placed at the end of the document.
624609
625−[^2]: Here's the long note. This one contains multiple blocks.
626−
610+[^2]:
611+ Here's the long note. This one contains multiple blocks.
612+
627613 Subsequent blocks are indented to show that they belong to the
628614 footnote (as with list items).
629−
615+
630616 { <code> }
631−
617+
632618 If you want, you can indent every line, but you can also be lazy
633619 and just indent the first line of each block.
634620
635−[^3]: This is *easier* to type. Inline notes may contain
621+[^3]:
622+ This is *easier* to type. Inline notes may contain
636623 [links](http://google.com) and `]` verbatim characters.
637624
638625[^4]: In quote.
639626
640−
641627[^5]: In list.
642628
643−
tests/writer.native+36−62
@@ -2,7 +2,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
22[ Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Str ".",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite",Str "."]
33, HorizontalRule
44, Header 1 [Str "Headers"]
5−, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] (Src "/url" "")]
5+, Header 2 [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
66, Header 3 [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
77, Header 4 [Str "Level",Space,Str "4"]
88, Header 5 [Str "Level",Space,Str "5"]
@@ -196,7 +196,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
196196, Header 1 [Str "Inline",Space,Str "Markup"]
197197, Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
198198, Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
199−, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] (Src "/url" "")],Str "."]
199+, Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
200200, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
201201, Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word",Str "."]
202202, Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em",Str "."]]]
@@ -208,7 +208,7 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
208208, Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters",Str "."]
209209, Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees",Str ".",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine",Str "."]]
210210, Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go",Str "."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70",Apostrophe,Str "s?"]
211−, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] (Ref [Str "1"])],Str "."]
211+, Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code "code"],Space,Str "and",Space,Str "a",Space,Quoted DoubleQuote [Link [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
212212, Para [Str "Some",Space,Str "dashes:",Space,Str "one",EmDash,Str "two",EmDash,Str "three",EmDash,Str "four",EmDash,Str "five",Str "."]
213213, Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5",EnDash,Str "7,",Space,Str "255",EnDash,Str "66,",Space,Str "1987",EnDash,Str "1999",Str "."]
214214, Para [Str "Ellipses",Ellipses,Str "and",Ellipses,Str "and",Ellipses,Str "."]
@@ -264,83 +264,57 @@ Pandoc (Meta [Str "Pandoc",Space,Str "Test",Space,Str "Suite"] ["John MacFarlane
264264, HorizontalRule
265265, Header 1 [Str "Links"]
266266, Header 2 [Str "Explicit"]
267−, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] (Src "/url/" ""),Str "."]
268−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title"),Str "."]
269−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title preceded by two spaces"),Str "."]
270−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title preceded by a tab"),Str "."]
271−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title with \"quotes\" in it")]
272−, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] (Src "/url/" "title with single quotes")]
273−, Para [Link [Str "with",Str "_",Str "underscore"] (Src "/url/with_underscore" "")]
274−, Para [Link [Str "Email",Space,Str "link"] (Src "mailto:nobody@nowhere.net" "")]
275−, Para [Link [Str "Empty"] (Src "" ""),Str "."]
267+, Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
268+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title"),Str "."]
269+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by two spaces"),Str "."]
270+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title preceded by a tab"),Str "."]
271+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with \"quotes\" in it")]
272+, Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/","title with single quotes")]
273+, Para [Link [Str "with",Str "_",Str "underscore"] ("/url/with_underscore","")]
274+, Para [Link [Str "Email",Space,Str "link"] ("mailto:nobody@nowhere.net","")]
275+, Para [Link [Str "Empty"] ("",""),Str "."]
276276, Header 2 [Str "Reference"]
277−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
278−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
279−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "a"]),Str "."]
280−, Key [Str "a"] (Src "/url/" "")
281−, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] (Ref [Str "b"]),Str "."]
282−, Para [Link [Str "b"] (Ref [Str "b"]),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
283−, Para [Str "Indented",Space,Link [Str "once"] (Ref [Str "once"]),Str "."]
284−, Para [Str "Indented",Space,Link [Str "twice"] (Ref [Str "twice"]),Str "."]
285−, Para [Str "Indented",Space,Link [Str "thrice"] (Ref [Str "thrice"]),Str "."]
277+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
278+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
279+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
280+, Para [Str "With",Space,Link [Str "embedded",Space,Str "[",Str "brackets",Str "]"] ("/url/",""),Str "."]
281+, Para [Link [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
282+, Para [Str "Indented",Space,Link [Str "once"] ("/url",""),Str "."]
283+, Para [Str "Indented",Space,Link [Str "twice"] ("/url",""),Str "."]
284+, Para [Str "Indented",Space,Link [Str "thrice"] ("/url",""),Str "."]
286285, Para [Str "This",Space,Str "should",Space,Str "[",Str "not",Str "]",Str "[",Str "]",Space,Str "be",Space,Str "a",Space,Str "link",Str "."]
287−, Key [Str "once"] (Src "/url" "")
288−, Key [Str "twice"] (Src "/url" "")
289−, Key [Str "thrice"] (Src "/url" "")
290286, CodeBlock "[not]: /url"
291−, Key [Str "b"] (Src "/url/" "")
292−, Para [Str "Foo",Space,Link [Str "bar"] (Ref [Str "bar"]),Str "."]
293−, Para [Str "Foo",Space,Link [Str "biz"] (Src "/url/" "Title with \"quote\" inside"),Str "."]
294−, Key [Str "bar"] (Src "/url/" "Title with \"quotes\" inside")
287+, Para [Str "Foo",Space,Link [Str "bar"] ("/url/","Title with \"quotes\" inside"),Str "."]
288+, Para [Str "Foo",Space,Link [Str "biz"] ("/url/","Title with \"quote\" inside"),Str "."]
295289, Header 2 [Str "With",Space,Str "ampersands"]
296−, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] (Ref [Str "1"]),Str "."]
297−, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] (Ref [Str "2"]),Str "."]
298−, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] (Src "/script?foo=1&bar=2" ""),Str "."]
299−, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] (Src "/script?foo=1&bar=2" ""),Str "."]
300−, Key [Str "1"] (Src "http://example.com/?foo=1&bar=2" "")
301−, Key [Str "2"] (Src "http://att.com/" "AT&T")
290+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
291+, Para [Str "Here",Apostrophe,Str "s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT",Str "&",Str "T"] ("http://att.com/","AT&T"),Str "."]
292+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
293+, Para [Str "Here",Apostrophe,Str "s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
302294, Header 2 [Str "Autolinks"]
303−, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1&bar=2"] (Src "http://example.com/?foo=1&bar=2" "")]
295+, Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
304296, BulletList
305297 [ [ Plain [Str "In",Space,Str "a",Space,Str "list?"] ]
306− , [ Plain [Link [Str "http://example.com/"] (Src "http://example.com/" "")] ]
298+ , [ Plain [Link [Str "http://example.com/"] ("http://example.com/","")] ]
307299 , [ Plain [Str "It",Space,Str "should",Str "."] ] ]
308−, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Str "nobody@nowhere.net"] (Src "mailto:nobody@nowhere.net" "")]
300+, Para [Str "An",Space,Str "e",Str "-",Str "mail",Space,Str "address:",Space,Link [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
309301, BlockQuote
310− [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] (Src "http://example.com/" "")] ]
302+ [ Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] ("http://example.com/","")] ]
311303
312304, Para [Str "Auto",Str "-",Str "links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code "<http://example.com/>"]
313305, CodeBlock "or here: <http://example.com/>"
314306, HorizontalRule
315307, Header 1 [Str "Images"]
316308, Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
317−, Para [Image [Str "lalune"] (Ref [Str "lalune"])]
318−, Key [Str "lalune"] (Src "lalune.jpg" "Voyage dans la Lune")
319−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] (Src "movie.jpg" ""),Space,Str "icon",Str "."]
309+, Para [Image [Str "lalune"] ("lalune.jpg","Voyage dans la Lune")]
310+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon",Str "."]
320311, HorizontalRule
321312, Header 1 [Str "Footnotes"]
322−, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",NoteRef "1",Space,Str "and",Space,Str "another",Str ".",NoteRef "2",Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",NoteRef "3"]
313+, Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."]],Space,Str "and",Space,Str "another",Str ".",Note [Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."],CodeBlock " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space",Str ".",Str "[",Str "^",Str "my",Space,Str "note",Str "]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note",Str ".",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters",Str "."]]]
323314, BlockQuote
324− [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",NoteRef "4"] ]
315+ [ Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes",Str ".",Note [Para [Str "In",Space,Str "quote",Str "."]]] ]
325316
326317, OrderedList
327− [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",NoteRef "5"] ]
328− ]
329−, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."]
330−, Note "1"
331− [ Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote",Str ".",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference",Str ".",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document",Str "."] ]
332−
333−, Note "2"
334− [ Para [Str "Here",Apostrophe,Str "s",Space,Str "the",Space,Str "long",Space,Str "note",Str ".",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks",Str "."]
335− , Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)",Str "."]
336− , CodeBlock " { <code> }"
337− , Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block",Str "."] ]
338−, Note "3"
339− [ Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type",Str ".",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] (Src "http://google.com" ""),Space,Str "and",Space,Code "]",Space,Str "verbatim",Space,Str "characters",Str "."] ]
340−
341−, Note "4"
342− [ Para [Str "In",Space,Str "quote",Str "."] ]
343−
344−, Note "5"
345− [ Para [Str "In",Space,Str "list",Str "."] ]
318+ [ [ Plain [Str "And",Space,Str "in",Space,Str "list",Space,Str "items",Str ".",Note [Para [Str "In",Space,Str "list",Str "."]]] ]
346319 ]
320+, Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented",Str "."] ]
tests/writer.rst+61−83
@@ -14,8 +14,8 @@ John Gruber's markdown test suite.
1414Headers
1515=======
1616
17−Level 2 with an `embedded link`_
18−--------------------------------
17+Level 2 with an `embedded link </url>`_
18+---------------------------------------
1919
2020Level 3 with *emphasis*
2121~~~~~~~~~~~~~~~~~~~~~~~
@@ -71,11 +71,11 @@ E-mail style:
7171 Code in a block quote:
7272
7373 ::
74−
74+
7575 sub status {
7676 print "working";
7777 }
78−
78+
7979 A list:
8080
8181 1. item one
@@ -97,11 +97,11 @@ Box-style:
9797 Example:
9898
9999 ::
100−
100+
101101 sub status {
102102 print "working";
103103 }
104−
104+
105105
106106 1. do laundry
107107 2. take out the trash
@@ -125,7 +125,7 @@ Code Blocks
125125Code:
126126
127127::
128−
128+
129129 ---- (should be four hyphens)
130130
131131 sub status {
@@ -133,15 +133,15 @@ Code:
133133 }
134134
135135 this code block is indented by one tab
136−
136+
137137And:
138138
139139::
140−
140+
141141 this code block is indented by two tabs
142142
143143 These should not be escaped: \$ \\ \> \[ \{
144−
144+
145145--------------
146146
147147Lists
@@ -244,9 +244,7 @@ Nested
244244------
245245
246246- Tab
247−
248247 - Tab
249−
250248 - Tab
251249
252250
@@ -255,7 +253,6 @@ Here's another:
255253
2562541. First
2572552. Second:
258−
259256 - Fee
260257 - Fie
261258 - Foe
@@ -373,17 +370,17 @@ foo
373370This should be a code block, though:
374371
375372::
376−
373+
377374 <div>
378375 foo
379376 </div>
380−
377+
381378As should this:
382379
383380::
384−
381+
385382 <div>foo</div>
386−
383+
387384Now, nested:
388385
389386
@@ -426,9 +423,9 @@ Multiline:
426423Code block:
427424
428425::
429−
426+
430427 <!-- Comment -->
431−
428+
432429Just plain comment, with trailing spaces on the line:
433430
434431
@@ -439,9 +436,9 @@ Just plain comment, with trailing spaces on the line:
439436Code:
440437
441438::
442−
439+
443440 <hr />
444−
441+
445442Hr's:
446443
447444
@@ -474,7 +471,7 @@ This is *emphasized*, and so *is this*.
474471
475472This is **strong**, and so **is this**.
476473
477−An *`emphasized link`_*.
474+An *`emphasized link </url>`_*.
478475
479476***This is strong and em.***
480477
@@ -499,7 +496,8 @@ Smart quotes, ellipses, dashes
499496
500497'He said, "I want to go."' Were you alive in the 70's?
501498
502−Here is some quoted '``code``' and a "`quoted link`_".
499+Here is some quoted '``code``' and a
500+"`quoted link <http://example.com/?foo=1&bar=2>`_".
503501
504502Some dashes: one--two--three--four--five.
505503
@@ -604,84 +602,88 @@ Links
604602Explicit
605603--------
606604
607−Just a `URL`_.
605+Just a `URL </url/>`_.
608606
609−`URL and title`_.
607+`URL and title </url/>`_.
610608
611−`URL and title`_.
609+`URL and title </url/>`_.
612610
613−`URL and title`_.
611+`URL and title </url/>`_.
614612
615−`URL and title`_
613+`URL and title </url/>`_
616614
617−`URL and title`_
615+`URL and title </url/>`_
618616
619−`with\_underscore`_
617+`with\_underscore </url/with_underscore>`_
620618
621−`Email link`_
619+`Email link <mailto:nobody@nowhere.net>`_
622620
623−`Empty`_.
621+`Empty <>`_.
624622
625623Reference
626624---------
627625
628−Foo `bar`_.
626+Foo `bar </url/>`_.
629627
630−Foo `bar`_.
628+Foo `bar </url/>`_.
631629
632−Foo `bar`_.
630+Foo `bar </url/>`_.
633631
634−With `embedded [brackets]`_.
632+With `embedded [brackets] </url/>`_.
635633
636−`b`_ by itself should be a link.
634+`b </url/>`_ by itself should be a link.
637635
638−Indented `once`_.
636+Indented `once </url>`_.
639637
640−Indented `twice`_.
638+Indented `twice </url>`_.
641639
642−Indented `thrice`_.
640+Indented `thrice </url>`_.
643641
644642This should [not][] be a link.
645643
646644::
647−
645+
648646 [not]: /url
649−
650−Foo `bar`_.
651647
652−Foo `biz`_.
648+Foo `bar </url/>`_.
649+
650+Foo `biz </url/>`_.
653651
654652With ampersands
655653---------------
656654
657−Here's a `link with an ampersand in the URL`_.
655+Here's a
656+`link with an ampersand in the URL <http://example.com/?foo=1&bar=2>`_.
658657
659−Here's a link with an amersand in the link text: `AT&T`_.
658+Here's a link with an amersand in the link text:
659+`AT&T <http://att.com/>`_.
660660
661−Here's an `inline link`_.
661+Here's an `inline link </script?foo=1&bar=2>`_.
662662
663−Here's an `inline link in pointy braces`_.
663+Here's an `inline link in pointy braces </script?foo=1&bar=2>`_.
664664
665665Autolinks
666666---------
667667
668−With an ampersand: `http://example.com/?foo=1&bar=2`_
668+With an ampersand:
669+`http://example.com/?foo=1&bar=2 <http://example.com/?foo=1&bar=2>`_
669670
670671- In a list?
671−- `http://example.com/`_
672+- `http://example.com/ <http://example.com/>`_
672673- It should.
673674
674−An e-mail address: `nobody@nowhere.net`_
675+An e-mail address:
676+`nobody@nowhere.net <mailto:nobody@nowhere.net>`_
675677
676− Blockquoted: `http://example.com/`_
678+ Blockquoted: `http://example.com/ <http://example.com/>`_
677679
678680
679681Auto-links should not occur here: ``<http://example.com/>``
680682
681683::
682−
684+
683685 or here: <http://example.com/>
684−
686+
685687--------------
686688
687689Images
@@ -721,44 +723,20 @@ indented.
721723 footnote (as with list items).
722724
723725 ::
724−
726+
725727 { <code> }
726−
728+
727729 If you want, you can indent every line, but you can also be lazy
728730 and just indent the first line of each block.
729731
730732.. [3]
731− This is *easier* to type. Inline notes may contain `links`_ and
732− ``]`` verbatim characters.
733+ This is *easier* to type. Inline notes may contain
734+ `links <http://google.com>`_ and ``]`` verbatim characters.
733735
734736.. [4] In quote.
735737
736738.. [5] In list.
737739
738740
739−.. _embedded link: /url
740−.. _emphasized link: /url
741−.. _quoted link: http://example.com/?foo=1&bar=2
742−.. _URL: /url/
743−.. _URL and title: /url/
744−.. _with\_underscore: /url/with_underscore
745−.. _Email link: mailto:nobody@nowhere.net
746−.. _Empty:
747−.. _bar: /url/
748−.. _embedded [brackets]: /url/
749−.. _b: /url/
750−.. _once: /url
751−.. _twice: /url
752−.. _thrice: /url
753−.. _biz: /url/
754−.. _link with an ampersand in the URL: http://example.com/?foo=1&bar=2
755−.. _AT&T: http://att.com/
756−.. _inline link: /script?foo=1&bar=2
757−.. _inline link in pointy braces: /script?foo=1&bar=2
758−.. _`http://example.com/?foo=1&bar=2`: http://example.com/?foo=1&bar=2
759−.. _`http://example.com/`: http://example.com/
760−.. _nobody@nowhere.net: mailto:nobody@nowhere.net
761741.. |lalune| image:: lalune.jpg
762−.. |movie| image:: movie.jpg
763−.. _links: http://google.com
764−
742+.. |movie| image:: movie.jpg