git.iko.soy/typeable/pandoc
on master help sign in
Added Textile writer module.
d073b16John MacFarlane
README+7−3
@@ -7,7 +7,7 @@ another, and a command-line tool that uses this library. It can read
7[markdown] and (subsets of) [reStructuredText], [HTML], and [LaTeX]; and
7[markdown] and (subsets of) [reStructuredText], [HTML], and [LaTeX]; and
8it can write plain text, [markdown], [reStructuredText], [HTML], [LaTeX],
8it can write plain text, [markdown], [reStructuredText], [HTML], [LaTeX],
9[ConTeXt], [RTF], [DocBook XML], [OpenDocument XML], [ODT], [GNU Texinfo],
9[ConTeXt], [RTF], [DocBook XML], [OpenDocument XML], [ODT], [GNU Texinfo],
10−[MediaWiki markup], [groff man] pages, and [S5] HTML slide shows.
10+[MediaWiki markup], [Textile], [groff man] pages, and [S5] HTML slide shows.
11Pandoc's enhanced version of markdown includes syntax for footnotes,
11Pandoc's enhanced version of markdown includes syntax for footnotes,
12tables, flexible ordered lists, definition lists, delimited code blocks,
12tables, flexible ordered lists, definition lists, delimited code blocks,
13superscript, subscript, strikeout, title blocks, automatic tables of
13superscript, subscript, strikeout, title blocks, automatic tables of
@@ -22,6 +22,7 @@ representation of the document, and a set of writers, which convert
22this native representation into a target format. Thus, adding an input
22this native representation into a target format. Thus, adding an input
23or output format requires only adding a reader or writer.
23or output format requires only adding a reader or writer.
24
24
25+[Textile]: http://thresholdstate.com/articles/4312/the-textile-reference-manual
25[markdown]: http://daringfireball.net/projects/markdown/
26[markdown]: http://daringfireball.net/projects/markdown/
26[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
27[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
27[S5]: http://meyerweb.com/eric/tools/s5/
28[S5]: http://meyerweb.com/eric/tools/s5/
@@ -90,8 +91,9 @@ Supported output formats include `markdown`, `latex`, `context`
90(ConTeXt), `html`, `rtf` (rich text format), `rst`
91(ConTeXt), `html`, `rtf` (rich text format), `rst`
91(reStructuredText), `docbook` (DocBook XML), `opendocument`
92(reStructuredText), `docbook` (DocBook XML), `opendocument`
92(OpenDocument XML), `odt` (OpenOffice text document), `texinfo`, (GNU
93(OpenDocument XML), `odt` (OpenOffice text document), `texinfo`, (GNU
93−Texinfo), `mediawiki` (MediaWiki markup), `man` (groff man), and `s5`
94+Texinfo), `mediawiki` (MediaWiki markup), `textile` (Textile), `man`
94−(which produces an HTML file that acts like powerpoint).
95+(groff man), and `s5` (which produces an HTML file that acts like
96+powerpoint).
95
97
96Supported input formats include `markdown`, `html`, `latex`, and `rst`.
98Supported input formats include `markdown`, `html`, `latex`, and `rst`.
97Note that the `rst` reader only parses a subset of reStructuredText
99Note that the `rst` reader only parses a subset of reStructuredText
@@ -1122,6 +1124,8 @@ In groff man output, it will be rendered verbatim without $'s.
1122
1124
1123In MediaWiki output, it will be rendered inside `<math>` tags.
1125In MediaWiki output, it will be rendered inside `<math>` tags.
1124
1126
1127+In Textile output, it will be rendered inside `<span class="math">` tags.
1128+
1125In RTF, Docbook, and OpenDocument output, it will be rendered, as far as
1129In RTF, Docbook, and OpenDocument output, it will be rendered, as far as
1126possible, using unicode characters, and will otherwise appear verbatim.
1130possible, using unicode characters, and will otherwise appear verbatim.
1127Unknown commands and symbols, and commands that cannot be dealt with
1131Unknown commands and symbols, and commands that cannot be dealt with
man/man1/pandoc.1.md+10−10
@@ -15,8 +15,8 @@ pandoc [*options*] [*input-file*]...
15Pandoc converts files from one markup format to another. It can
15Pandoc converts files from one markup format to another. It can
16read markdown and (subsets of) reStructuredText, HTML, and LaTeX, and
16read markdown and (subsets of) reStructuredText, HTML, and LaTeX, and
17it can write plain text, markdown, reStructuredText, HTML, LaTeX,
17it can write plain text, markdown, reStructuredText, HTML, LaTeX,
18−ConTeXt, Texinfo, groff man, MediaWiki markup, RTF, OpenDocument XML,
18+ConTeXt, Texinfo, groff man, MediaWiki markup, Textile, RTF,
19−ODT, DocBook XML, and S5 HTML slide shows.
19+OpenDocument XML, ODT, DocBook XML, and S5 HTML slide shows.
20
20
21If no *input-file* is specified, input is read from *stdin*.
21If no *input-file* is specified, input is read from *stdin*.
22Otherwise, the *input-files* are concatenated (with a blank
22Otherwise, the *input-files* are concatenated (with a blank
@@ -72,14 +72,14 @@ should pipe input and output through `iconv`:
72: Specify output format. *FORMAT* can be `native` (native Haskell),
72: Specify output format. *FORMAT* can be `native` (native Haskell),
73 `plain` (plain text), `markdown` (markdown), `rst` (reStructuredText),
73 `plain` (plain text), `markdown` (markdown), `rst` (reStructuredText),
74 `html` (HTML), `latex` (LaTeX), `context` (ConTeXt), `man` (groff man),
74 `html` (HTML), `latex` (LaTeX), `context` (ConTeXt), `man` (groff man),
75− `mediawiki` (MediaWiki markup), `texinfo` (GNU Texinfo),
75+ `mediawiki` (MediaWiki markup), `textile` (Textile), `texinfo` (GNU
76− `docbook` (DocBook XML), `opendocument` (OpenDocument XML),
76+ Texinfo), `docbook` (DocBook XML), `opendocument` (OpenDocument
77− `odt` (OpenOffice text document), `s5` (S5 HTML and javascript slide
77+ XML), `odt` (OpenOffice text document), `s5` (S5 HTML and javascript
78− show), or `rtf` (rich text format). Note that `odt` output will not
78+ slide show), or `rtf` (rich text format). Note that `odt` output
79− be directed to *stdout*; an output filename must be specified using
79+ will not be directed to *stdout*; an output filename must be
80− the `-o/--output` option. If `+lhs` is appended to `markdown`,
80+ specified using the `-o/--output` option. If `+lhs` is appended to
81− `rst`, `latex`, or `html`, the output will be rendered as literate
81+ `markdown`, `rst`, `latex`, or `html`, the output will be rendered
82− Haskell source.
82+ as literate Haskell source.
83
83
84-s, \--standalone
84-s, \--standalone
85: Produce output with an appropriate header and footer (e.g. a
85: Produce output with an appropriate header and footer (e.g. a
pandoc.cabal+5−1
@@ -18,7 +18,7 @@ Description: Pandoc is a Haskell library for converting from one markup
18 this library. It can read markdown and (subsets of)
18 this library. It can read markdown and (subsets of)
19 reStructuredText, HTML, and LaTeX, and it can write
19 reStructuredText, HTML, and LaTeX, and it can write
20 markdown, reStructuredText, HTML, LaTeX, ConTeXt, Docbook,
20 markdown, reStructuredText, HTML, LaTeX, ConTeXt, Docbook,
21− OpenDocument, ODT, RTF, MediaWiki, groff man pages, and
21+ OpenDocument, ODT, RTF, MediaWiki, Textile, groff man pages, and
22 S5 HTML slide shows.
22 S5 HTML slide shows.
23 .
23 .
24 Pandoc extends standard markdown syntax with footnotes,
24 Pandoc extends standard markdown syntax with footnotes,
@@ -42,6 +42,7 @@ Data-Files:
42 templates/man.template, templates/markdown.template,
42 templates/man.template, templates/markdown.template,
43 templates/rst.template, templates/plain.template,
43 templates/rst.template, templates/plain.template,
44 templates/mediawiki.template, templates/rtf.template,
44 templates/mediawiki.template, templates/rtf.template,
45+ templates/textile.template
45 -- data for ODT writer
46 -- data for ODT writer
46 reference.odt,
47 reference.odt,
47 -- data for LaTeXMathML writer
48 -- data for LaTeXMathML writer
@@ -87,6 +88,7 @@ Extra-Source-Files:
87 tests/tables.plain,
88 tests/tables.plain,
88 tests/tables.markdown,
89 tests/tables.markdown,
89 tests/tables.mediawiki,
90 tests/tables.mediawiki,
91+ tests/tables.textile,
90 tests/tables.native,
92 tests/tables.native,
91 tests/tables.opendocument,
93 tests/tables.opendocument,
92 tests/tables.texinfo,
94 tests/tables.texinfo,
@@ -104,6 +106,7 @@ Extra-Source-Files:
104 tests/writer.markdown,
106 tests/writer.markdown,
105 tests/writer.plain,
107 tests/writer.plain,
106 tests/writer.mediawiki,
108 tests/writer.mediawiki,
109+ tests/writer.textile,
107 tests/writer.native,
110 tests/writer.native,
108 tests/writer.opendocument,
111 tests/writer.opendocument,
109 tests/writer.rst,
112 tests/writer.rst,
@@ -180,6 +183,7 @@ Library
180 Text.Pandoc.Writers.Man,
183 Text.Pandoc.Writers.Man,
181 Text.Pandoc.Writers.Markdown,
184 Text.Pandoc.Writers.Markdown,
182 Text.Pandoc.Writers.RST,
185 Text.Pandoc.Writers.RST,
186+ Text.Pandoc.Writers.Textile,
183 Text.Pandoc.Writers.MediaWiki,
187 Text.Pandoc.Writers.MediaWiki,
184 Text.Pandoc.Writers.RTF,
188 Text.Pandoc.Writers.RTF,
185 Text.Pandoc.Writers.S5,
189 Text.Pandoc.Writers.S5,
src/Text/Pandoc.hs+2
@@ -85,6 +85,7 @@ module Text.Pandoc
85 , writeOpenDocument
85 , writeOpenDocument
86 , writeMan
86 , writeMan
87 , writeMediaWiki
87 , writeMediaWiki
88+ , writeTextile
88 , writeRTF
89 , writeRTF
89 , prettyPandoc
90 , prettyPandoc
90 -- * Writer options used in writers
91 -- * Writer options used in writers
@@ -114,6 +115,7 @@ import Text.Pandoc.Writers.OpenDocument
114import Text.Pandoc.Writers.Man
115import Text.Pandoc.Writers.Man
115import Text.Pandoc.Writers.RTF
116import Text.Pandoc.Writers.RTF
116import Text.Pandoc.Writers.MediaWiki
117import Text.Pandoc.Writers.MediaWiki
118+import Text.Pandoc.Writers.Textile
117import Text.Pandoc.Templates
119import Text.Pandoc.Templates
118import Text.Pandoc.Shared
120import Text.Pandoc.Shared
119import Data.Version (showVersion)
121import Data.Version (showVersion)
src/Text/Pandoc/Writers/Textile.hsnew file+413
@@ -0,0 +1,413 @@
1+{-
2+Copyright (C) 2010 John MacFarlane <jgm@berkeley.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Writers.Textile
21+ Copyright : Copyright (C) 2010 John MacFarlane
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : John MacFarlane <jgm@berkeley.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+Conversion of 'Pandoc' documents to Textile markup.
29+
30+Textile: <http://thresholdstate.com/articles/4312/the-textile-reference-manual>
31+-}
32+module Text.Pandoc.Writers.Textile ( writeTextile ) where
33+import Text.Pandoc.Definition
34+import Text.Pandoc.Shared
35+import Text.Pandoc.Templates (renderTemplate)
36+import Text.Pandoc.XML ( escapeStringForXML )
37+import Data.List ( intercalate )
38+import Control.Monad.State
39+import Data.Char ( isSpace )
40+
41+data WriterState = WriterState {
42+ stNotes :: [String] -- Footnotes
43+ , stListLevel :: [Char] -- String at beginning of list items, e.g. "**"
44+ , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
45+ }
46+
47+-- | Convert Pandoc to Textile.
48+writeTextile :: WriterOptions -> Pandoc -> String
49+writeTextile opts document =
50+ evalState (pandocToTextile opts document)
51+ (WriterState { stNotes = [], stListLevel = [], stUseTags = False })
52+
53+-- | Return Textile representation of document.
54+pandocToTextile :: WriterOptions -> Pandoc -> State WriterState String
55+pandocToTextile opts (Pandoc _ blocks) = do
56+ body <- blockListToTextile opts blocks
57+ notes <- liftM (unlines . reverse . stNotes) get
58+ let main = body ++ if null notes then "" else ("\n\n" ++ notes)
59+ let context = writerVariables opts ++ [ ("body", main) ]
60+ if writerStandalone opts
61+ then return $ renderTemplate context $ writerTemplate opts
62+ else return main
63+
64+withUseTags :: State WriterState a -> State WriterState a
65+withUseTags action = do
66+ oldUseTags <- liftM stUseTags get
67+ modify $ \s -> s { stUseTags = True }
68+ result <- action
69+ modify $ \s -> s { stUseTags = oldUseTags }
70+ return result
71+
72+-- | Escape one character as needed for Textile.
73+escapeCharForTextile :: Char -> String
74+escapeCharForTextile x = case x of
75+ '&' -> "&amp;"
76+ '<' -> "&lt;"
77+ '>' -> "&gt;"
78+ '"' -> "&quot;"
79+ '*' -> "&#42;"
80+ '_' -> "&#95;"
81+ '@' -> "&#64;"
82+ '|' -> "&#124;"
83+ c -> [c]
84+
85+-- | Escape string as needed for Textile.
86+escapeStringForTextile :: String -> String
87+escapeStringForTextile = concatMap escapeCharForTextile
88+
89+-- | Convert Pandoc block element to Textile.
90+blockToTextile :: WriterOptions -- ^ Options
91+ -> Block -- ^ Block element
92+ -> State WriterState String
93+
94+blockToTextile _ Null = return ""
95+
96+blockToTextile opts (Plain inlines) =
97+ inlineListToTextile opts inlines
98+
99+blockToTextile opts (Para [Image txt (src,tit)]) = do
100+ capt <- blockToTextile opts (Para txt)
101+ im <- inlineToTextile opts (Image txt (src,tit))
102+ return $ im ++ "\n" ++ capt
103+
104+blockToTextile opts (Para inlines) = do
105+ useTags <- liftM stUseTags get
106+ listLevel <- liftM stListLevel get
107+ contents <- inlineListToTextile opts inlines
108+ return $ if useTags
109+ then " <p>" ++ contents ++ "</p>"
110+ else contents ++ if null listLevel then "\n" else ""
111+
112+blockToTextile _ (RawHtml str) = return str
113+
114+blockToTextile _ HorizontalRule = return "<hr />\n"
115+
116+blockToTextile opts (Header level inlines) = do
117+ contents <- inlineListToTextile opts inlines
118+ let prefix = 'h' : (show level ++ ". ")
119+ return $ prefix ++ contents ++ "\n"
120+
121+blockToTextile _ (CodeBlock (_,classes,_) str) =
122+ return $ "bc" ++ classes' ++ dots ++ escapeStringForXML str ++ "\n"
123+ where classes' = if null classes
124+ then ""
125+ else "(" ++ unwords classes ++ ")"
126+ dots = if any isBlank (lines str)
127+ then ".. "
128+ else ". "
129+ isBlank = all isSpace
130+
131+blockToTextile opts (BlockQuote bs@[Para _]) = do
132+ contents <- blockListToTextile opts bs
133+ return $ "bq. " ++ contents
134+
135+blockToTextile opts (BlockQuote blocks) = do
136+ contents <- blockListToTextile opts blocks
137+ return $ "<blockquote>\n\n" ++ contents ++ "\n</blockquote>\n"
138+
139+blockToTextile opts (Table [] aligns widths headers rows') |
140+ all (==0) widths && all (`elem` [AlignLeft,AlignDefault]) aligns = do
141+ hs <- mapM (liftM (("_. " ++) . stripTrailingNewlines) . blockListToTextile opts) headers
142+ let cellsToRow cells = "|" ++ intercalate "|" cells ++ "|"
143+ let header = if all null headers then "" else cellsToRow hs
144+ let rowToCells = mapM (liftM stripTrailingNewlines . blockListToTextile opts)
145+ bs <- mapM rowToCells rows'
146+ let body = unlines $ map cellsToRow bs
147+ return $ header ++ "\n" ++ body ++ "\n"
148+
149+blockToTextile opts (Table capt aligns widths headers rows') = do
150+ let alignStrings = map alignmentToString aligns
151+ captionDoc <- if null capt
152+ then return ""
153+ else do
154+ c <- inlineListToTextile opts capt
155+ return $ " <caption>" ++ c ++ "</caption>\n"
156+ let percent w = show (truncate (100*w) :: Integer) ++ "%"
157+ let coltags = if all (== 0.0) widths
158+ then ""
159+ else unlines $ map
160+ (\w -> " <col width=\"" ++ percent w ++ "\" />") widths
161+ head' <- if all null headers
162+ then return ""
163+ else do
164+ hs <- tableRowToTextile opts alignStrings 0 headers
165+ return $ " <thead>\n" ++ hs ++ "\n </thead>\n"
166+ body' <- zipWithM (tableRowToTextile opts alignStrings) [1..] rows'
167+ return $ " <table>\n" ++ captionDoc ++ coltags ++ head' ++
168+ " <tbody>\n" ++ unlines body' ++ " </tbody>\n </table>\n"
169+
170+blockToTextile opts x@(BulletList items) = do
171+ oldUseTags <- liftM stUseTags get
172+ let useTags = oldUseTags || not (isSimpleList x)
173+ if useTags
174+ then do
175+ contents <- withUseTags $ mapM (listItemToTextile opts) items
176+ return $ " <ul>\n" ++ vcat contents ++ " </ul>\n"
177+ else do
178+ modify $ \s -> s { stListLevel = stListLevel s ++ "*" }
179+ contents <- mapM (listItemToTextile opts) items
180+ modify $ \s -> s { stListLevel = init (stListLevel s) }
181+ return $ vcat contents ++ "\n"
182+
183+blockToTextile opts x@(OrderedList attribs items) = do
184+ oldUseTags <- liftM stUseTags get
185+ let useTags = oldUseTags || not (isSimpleList x)
186+ if useTags
187+ then do
188+ contents <- withUseTags $ mapM (listItemToTextile opts) items
189+ return $ " <ol" ++ listAttribsToString attribs ++ ">\n" ++ vcat contents ++
190+ " </ol>\n"
191+ else do
192+ modify $ \s -> s { stListLevel = stListLevel s ++ "#" }
193+ contents <- mapM (listItemToTextile opts) items
194+ modify $ \s -> s { stListLevel = init (stListLevel s) }
195+ return $ vcat contents ++ "\n"
196+
197+blockToTextile opts (DefinitionList items) = do
198+ contents <- withUseTags $ mapM (definitionListItemToTextile opts) items
199+ return $ " <dl>\n" ++ vcat contents ++ " </dl>\n"
200+
201+-- Auxiliary functions for lists:
202+
203+-- | Convert ordered list attributes to HTML attribute string
204+listAttribsToString :: ListAttributes -> String
205+listAttribsToString (startnum, numstyle, _) =
206+ let numstyle' = camelCaseToHyphenated $ show numstyle
207+ in (if startnum /= 1
208+ then " start=\"" ++ show startnum ++ "\""
209+ else "") ++
210+ (if numstyle /= DefaultStyle
211+ then " style=\"list-style-type: " ++ numstyle' ++ ";\""
212+ else "")
213+
214+-- | Convert bullet or ordered list item (list of blocks) to Textile.
215+listItemToTextile :: WriterOptions -> [Block] -> State WriterState String
216+listItemToTextile opts items = do
217+ contents <- blockListToTextile opts items
218+ useTags <- get >>= return . stUseTags
219+ if useTags
220+ then return $ " <li>" ++ contents ++ "</li>"
221+ else do
222+ marker <- get >>= return . stListLevel
223+ return $ marker ++ " " ++ contents
224+
225+-- | Convert definition list item (label, list of blocks) to Textile.
226+definitionListItemToTextile :: WriterOptions
227+ -> ([Inline],[[Block]])
228+ -> State WriterState String
229+definitionListItemToTextile opts (label, items) = do
230+ labelText <- inlineListToTextile opts label
231+ contents <- mapM (blockListToTextile opts) items
232+ return $ " <dt>" ++ labelText ++ "</dt>\n" ++
233+ (intercalate "\n" $ map (\d -> " <dd>" ++ d ++ "</dd>") contents)
234+
235+-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
236+isSimpleList :: Block -> Bool
237+isSimpleList x =
238+ case x of
239+ BulletList items -> all isSimpleListItem items
240+ OrderedList (num, sty, _) items -> all isSimpleListItem items &&
241+ num == 1 && sty `elem` [DefaultStyle, Decimal]
242+ _ -> False
243+
244+-- | True if list item can be handled with the simple wiki syntax. False if
245+-- HTML tags will be needed.
246+isSimpleListItem :: [Block] -> Bool
247+isSimpleListItem [] = True
248+isSimpleListItem [x] =
249+ case x of
250+ Plain _ -> True
251+ Para _ -> True
252+ BulletList _ -> isSimpleList x
253+ OrderedList _ _ -> isSimpleList x
254+ _ -> False
255+isSimpleListItem [x, y] | isPlainOrPara x =
256+ case y of
257+ BulletList _ -> isSimpleList y
258+ OrderedList _ _ -> isSimpleList y
259+ _ -> False
260+isSimpleListItem _ = False
261+
262+isPlainOrPara :: Block -> Bool
263+isPlainOrPara (Plain _) = True
264+isPlainOrPara (Para _) = True
265+isPlainOrPara _ = False
266+
267+-- | Concatenates strings with line breaks between them.
268+vcat :: [String] -> String
269+vcat = intercalate "\n"
270+
271+-- Auxiliary functions for tables. (TODO: these are common to HTML, MediaWiki,
272+-- and Textile writers, and should be abstracted out.)
273+
274+tableRowToTextile :: WriterOptions
275+ -> [String]
276+ -> Int
277+ -> [[Block]]
278+ -> State WriterState String
279+tableRowToTextile opts alignStrings rownum cols' = do
280+ let celltype = if rownum == 0 then "th" else "td"
281+ let rowclass = case rownum of
282+ 0 -> "header"
283+ x | x `rem` 2 == 1 -> "odd"
284+ _ -> "even"
285+ cols'' <- sequence $ zipWith
286+ (\alignment item -> tableItemToTextile opts celltype alignment item)
287+ alignStrings cols'
288+ return $ "<tr class=\"" ++ rowclass ++ "\">\n" ++ unlines cols'' ++ "</tr>"
289+
290+alignmentToString :: Alignment -> [Char]
291+alignmentToString alignment = case alignment of
292+ AlignLeft -> "left"
293+ AlignRight -> "right"
294+ AlignCenter -> "center"
295+ AlignDefault -> "left"
296+
297+tableItemToTextile :: WriterOptions
298+ -> String
299+ -> String
300+ -> [Block]
301+ -> State WriterState String
302+tableItemToTextile opts celltype align' item = do
303+ let mkcell x = "<" ++ celltype ++ " align=\"" ++ align' ++ "\">" ++
304+ x ++ "</" ++ celltype ++ ">"
305+ contents <- blockListToTextile opts item
306+ return $ mkcell contents
307+
308+-- | Convert list of Pandoc block elements to Textile.
309+blockListToTextile :: WriterOptions -- ^ Options
310+ -> [Block] -- ^ List of block elements
311+ -> State WriterState String
312+blockListToTextile opts blocks =
313+ mapM (blockToTextile opts) blocks >>= return . vcat
314+
315+-- | Convert list of Pandoc inline elements to Textile.
316+inlineListToTextile :: WriterOptions -> [Inline] -> State WriterState String
317+inlineListToTextile opts lst =
318+ mapM (inlineToTextile opts) lst >>= return . concat
319+
320+-- | Convert Pandoc inline element to Textile.
321+inlineToTextile :: WriterOptions -> Inline -> State WriterState String
322+
323+inlineToTextile opts (Emph lst) = do
324+ contents <- inlineListToTextile opts lst
325+ return $ if '_' `elem` contents
326+ then "<em>" ++ contents ++ "</em>"
327+ else "_" ++ contents ++ "_"
328+
329+inlineToTextile opts (Strong lst) = do
330+ contents <- inlineListToTextile opts lst
331+ return $ if '*' `elem` contents
332+ then "<strong>" ++ contents ++ "</strong>"
333+ else "*" ++ contents ++ "*"
334+
335+inlineToTextile opts (Strikeout lst) = do
336+ contents <- inlineListToTextile opts lst
337+ return $ if '-' `elem` contents
338+ then "<del>" ++ contents ++ "</del>"
339+ else "-" ++ contents ++ "-"
340+
341+inlineToTextile opts (Superscript lst) = do
342+ contents <- inlineListToTextile opts lst
343+ return $ if '^' `elem` contents
344+ then "<sup>" ++ contents ++ "</sup>"
345+ else "^" ++ contents ++ "^"
346+
347+inlineToTextile opts (Subscript lst) = do
348+ contents <- inlineListToTextile opts lst
349+ return $ if '~' `elem` contents
350+ then "<sub>" ++ contents ++ "</sub>"
351+ else "~" ++ contents ++ "~"
352+
353+inlineToTextile opts (SmallCaps lst) = inlineListToTextile opts lst
354+
355+inlineToTextile opts (Quoted SingleQuote lst) = do
356+ contents <- inlineListToTextile opts lst
357+ return $ "'" ++ contents ++ "'"
358+
359+inlineToTextile opts (Quoted DoubleQuote lst) = do
360+ contents <- inlineListToTextile opts lst
361+ return $ "\"" ++ contents ++ "\""
362+
363+inlineToTextile opts (Cite _ lst) = inlineListToTextile opts lst
364+
365+inlineToTextile _ EmDash = return " -- "
366+
367+inlineToTextile _ EnDash = return " - "
368+
369+inlineToTextile _ Apostrophe = return "'"
370+
371+inlineToTextile _ Ellipses = return "..."
372+
373+inlineToTextile _ (Code str) =
374+ return $ if '@' `elem` str
375+ then "<tt>" ++ escapeStringForXML str ++ "</tt>"
376+ else "@" ++ escapeStringForXML str ++ "@"
377+
378+inlineToTextile _ (Str str) = return $ escapeStringForTextile str
379+
380+inlineToTextile _ (Math _ str) =
381+ return $ "<span class=\"math\">" ++ escapeStringForXML str ++ "</math>"
382+
383+inlineToTextile _ (TeX _) = return ""
384+
385+inlineToTextile _ (HtmlInline str) = return str
386+
387+inlineToTextile _ (LineBreak) = return "\n"
388+
389+inlineToTextile _ Space = return " "
390+
391+inlineToTextile opts (Link txt (src, _)) = do
392+ label <- case txt of
393+ [Code s] -> return s
394+ _ -> inlineListToTextile opts txt
395+ return $ "\"" ++ label ++ "\":" ++ src
396+
397+inlineToTextile opts (Image alt (source, tit)) = do
398+ alt' <- inlineListToTextile opts alt
399+ let txt = if null tit
400+ then if null alt'
401+ then ""
402+ else "(" ++ alt' ++ ")"
403+ else "(" ++ tit ++ ")"
404+ return $ "!" ++ source ++ txt ++ "!"
405+
406+inlineToTextile opts (Note contents) = do
407+ curNotes <- liftM stNotes get
408+ let newnum = length curNotes + 1
409+ contents' <- blockListToTextile opts contents
410+ let thisnote = "fn" ++ show newnum ++ ". " ++ contents' ++ "\n"
411+ modify $ \s -> s { stNotes = thisnote : curNotes }
412+ return $ "[" ++ show newnum ++ "]"
413+ -- note - may not work for notes with multiple blocks
src/pandoc.hs+1
@@ -120,6 +120,7 @@ writers = [("native" , writeDoc)
120 ,("rst" , writeRST)
120 ,("rst" , writeRST)
121 ,("rst+lhs" , writeRST)
121 ,("rst+lhs" , writeRST)
122 ,("mediawiki" , writeMediaWiki)
122 ,("mediawiki" , writeMediaWiki)
123+ ,("textile" , writeTextile)
123 ,("rtf" , writeRTF)
124 ,("rtf" , writeRTF)
124 ]
125 ]
125
126
templates/textile.templatenew file+12
@@ -0,0 +1,12 @@
1+$if(legacy-header)$
2+$legacy-header$
3+$endif$
4+$for(include-before)$
5+$include-before$
6+
7+$endfor$
8+$body$
9+$for(include-after)$
10+
11+$include-after$
12+$endfor$
tests/RunTests.hs+1
@@ -60,6 +60,7 @@ writerFormats = [ "native"
60 , "markdown"
60 , "markdown"
61 , "rst"
61 , "rst"
62 , "mediawiki"
62 , "mediawiki"
63+ , "textile"
63 , "rtf"
64 , "rtf"
64 ]
65 ]
65
66
tests/tables.textilenew file+212
@@ -0,0 +1,212 @@
1+Simple table with caption:
2+
3+ <table>
4+ <caption>Demonstration of simple table syntax.</caption>
5+ <thead>
6+<tr class="header">
7+<th align="right">Right</th>
8+<th align="left">Left</th>
9+<th align="center">Center</th>
10+<th align="left">Default</th>
11+</tr>
12+ </thead>
13+ <tbody>
14+<tr class="odd">
15+<td align="right">12</td>
16+<td align="left">12</td>
17+<td align="center">12</td>
18+<td align="left">12</td>
19+</tr>
20+<tr class="even">
21+<td align="right">123</td>
22+<td align="left">123</td>
23+<td align="center">123</td>
24+<td align="left">123</td>
25+</tr>
26+<tr class="odd">
27+<td align="right">1</td>
28+<td align="left">1</td>
29+<td align="center">1</td>
30+<td align="left">1</td>
31+</tr>
32+ </tbody>
33+ </table>
34+
35+Simple table without caption:
36+
37+ <table>
38+ <thead>
39+<tr class="header">
40+<th align="right">Right</th>
41+<th align="left">Left</th>
42+<th align="center">Center</th>
43+<th align="left">Default</th>
44+</tr>
45+ </thead>
46+ <tbody>
47+<tr class="odd">
48+<td align="right">12</td>
49+<td align="left">12</td>
50+<td align="center">12</td>
51+<td align="left">12</td>
52+</tr>
53+<tr class="even">
54+<td align="right">123</td>
55+<td align="left">123</td>
56+<td align="center">123</td>
57+<td align="left">123</td>
58+</tr>
59+<tr class="odd">
60+<td align="right">1</td>
61+<td align="left">1</td>
62+<td align="center">1</td>
63+<td align="left">1</td>
64+</tr>
65+ </tbody>
66+ </table>
67+
68+Simple table indented two spaces:
69+
70+ <table>
71+ <caption>Demonstration of simple table syntax.</caption>
72+ <thead>
73+<tr class="header">
74+<th align="right">Right</th>
75+<th align="left">Left</th>
76+<th align="center">Center</th>
77+<th align="left">Default</th>
78+</tr>
79+ </thead>
80+ <tbody>
81+<tr class="odd">
82+<td align="right">12</td>
83+<td align="left">12</td>
84+<td align="center">12</td>
85+<td align="left">12</td>
86+</tr>
87+<tr class="even">
88+<td align="right">123</td>
89+<td align="left">123</td>
90+<td align="center">123</td>
91+<td align="left">123</td>
92+</tr>
93+<tr class="odd">
94+<td align="right">1</td>
95+<td align="left">1</td>
96+<td align="center">1</td>
97+<td align="left">1</td>
98+</tr>
99+ </tbody>
100+ </table>
101+
102+Multiline table with caption:
103+
104+ <table>
105+ <caption>Here's the caption. It may span multiple lines.</caption>
106+ <col width="15%" />
107+ <col width="13%" />
108+ <col width="16%" />
109+ <col width="33%" />
110+ <thead>
111+<tr class="header">
112+<th align="center">Centered Header</th>
113+<th align="left">Left Aligned</th>
114+<th align="right">Right Aligned</th>
115+<th align="left">Default aligned</th>
116+</tr>
117+ </thead>
118+ <tbody>
119+<tr class="odd">
120+<td align="center">First</td>
121+<td align="left">row</td>
122+<td align="right">12.0</td>
123+<td align="left">Example of a row that spans multiple lines.</td>
124+</tr>
125+<tr class="even">
126+<td align="center">Second</td>
127+<td align="left">row</td>
128+<td align="right">5.0</td>
129+<td align="left">Here's another one. Note the blank line between rows.</td>
130+</tr>
131+ </tbody>
132+ </table>
133+
134+Multiline table without caption:
135+
136+ <table>
137+ <col width="15%" />
138+ <col width="13%" />
139+ <col width="16%" />
140+ <col width="33%" />
141+ <thead>
142+<tr class="header">
143+<th align="center">Centered Header</th>
144+<th align="left">Left Aligned</th>
145+<th align="right">Right Aligned</th>
146+<th align="left">Default aligned</th>
147+</tr>
148+ </thead>
149+ <tbody>
150+<tr class="odd">
151+<td align="center">First</td>
152+<td align="left">row</td>
153+<td align="right">12.0</td>
154+<td align="left">Example of a row that spans multiple lines.</td>
155+</tr>
156+<tr class="even">
157+<td align="center">Second</td>
158+<td align="left">row</td>
159+<td align="right">5.0</td>
160+<td align="left">Here's another one. Note the blank line between rows.</td>
161+</tr>
162+ </tbody>
163+ </table>
164+
165+Table without column headers:
166+
167+ <table>
168+ <tbody>
169+<tr class="odd">
170+<td align="right">12</td>
171+<td align="left">12</td>
172+<td align="center">12</td>
173+<td align="right">12</td>
174+</tr>
175+<tr class="even">
176+<td align="right">123</td>
177+<td align="left">123</td>
178+<td align="center">123</td>
179+<td align="right">123</td>
180+</tr>
181+<tr class="odd">
182+<td align="right">1</td>
183+<td align="left">1</td>
184+<td align="center">1</td>
185+<td align="right">1</td>
186+</tr>
187+ </tbody>
188+ </table>
189+
190+Multiline table without column headers:
191+
192+ <table>
193+ <col width="15%" />
194+ <col width="13%" />
195+ <col width="16%" />
196+ <col width="33%" />
197+ <tbody>
198+<tr class="odd">
199+<td align="center">First</td>
200+<td align="left">row</td>
201+<td align="right">12.0</td>
202+<td align="left">Example of a row that spans multiple lines.</td>
203+</tr>
204+<tr class="even">
205+<td align="center">Second</td>
206+<td align="left">row</td>
207+<td align="right">5.0</td>
208+<td align="left">Here's another one. Note the blank line between rows.</td>
209+</tr>
210+ </tbody>
211+ </table>
212+
tests/writer.textilenew file+683
@@ -0,0 +1,683 @@
1+This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
2+
3+<hr />
4+
5+h1. Headers
6+
7+h2. Level 2 with an "embedded link":/url
8+
9+h3. Level 3 with _emphasis_
10+
11+h4. Level 4
12+
13+h5. Level 5
14+
15+h1. Level 1
16+
17+h2. Level 2 with _emphasis_
18+
19+h3. Level 3
20+
21+with no blank line
22+
23+h2. Level 2
24+
25+with no blank line
26+
27+<hr />
28+
29+h1. Paragraphs
30+
31+Here's a regular paragraph.
32+
33+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like a list item.
34+
35+Here's one with a bullet. &#42; criminey.
36+
37+There should be a hard line break
38+here.
39+
40+<hr />
41+
42+h1. Block Quotes
43+
44+E-mail style:
45+
46+bq. This is a block quote. It is pretty short.
47+
48+<blockquote>
49+
50+Code in a block quote:
51+
52+bc. sub status {
53+ print &quot;working&quot;;
54+}
55+
56+A list:
57+
58+# item one
59+# item two
60+
61+Nested block quotes:
62+
63+bq. nested
64+
65+bq. nested
66+
67+</blockquote>
68+
69+This should not be a block quote: 2 &gt; 1.
70+
71+And a following paragraph.
72+
73+<hr />
74+
75+h1. Code Blocks
76+
77+Code:
78+
79+bc.. ---- (should be four hyphens)
80+
81+sub status {
82+ print &quot;working&quot;;
83+}
84+
85+this code block is indented by one tab
86+
87+And:
88+
89+bc.. this code block is indented by two tabs
90+
91+These should not be escaped: \$ \\ \&gt; \[ \{
92+
93+<hr />
94+
95+h1. Lists
96+
97+h2. Unordered
98+
99+Asterisks tight:
100+
101+* asterisk 1
102+* asterisk 2
103+* asterisk 3
104+
105+Asterisks loose:
106+
107+* asterisk 1
108+* asterisk 2
109+* asterisk 3
110+
111+Pluses tight:
112+
113+* Plus 1
114+* Plus 2
115+* Plus 3
116+
117+Pluses loose:
118+
119+* Plus 1
120+* Plus 2
121+* Plus 3
122+
123+Minuses tight:
124+
125+* Minus 1
126+* Minus 2
127+* Minus 3
128+
129+Minuses loose:
130+
131+* Minus 1
132+* Minus 2
133+* Minus 3
134+
135+h2. Ordered
136+
137+Tight:
138+
139+# First
140+# Second
141+# Third
142+
143+and:
144+
145+# One
146+# Two
147+# Three
148+
149+Loose using tabs:
150+
151+# First
152+# Second
153+# Third
154+
155+and using spaces:
156+
157+# One
158+# Two
159+# Three
160+
161+Multiple paragraphs:
162+
163+ <ol style="list-style-type: decimal;">
164+ <li> <p>Item 1, graf one.</p>
165+ <p>Item 1. graf two. The quick brown fox jumped over the lazy dog's back.</p></li>
166+ <li> <p>Item 2.</p></li>
167+ <li> <p>Item 3.</p></li> </ol>
168+
169+h2. Nested
170+
171+* Tab
172+** Tab
173+*** Tab
174+
175+
176+
177+Here's another:
178+
179+# First
180+# Second:
181+#* Fee
182+#* Fie
183+#* Foe
184+
185+# Third
186+
187+Same thing but with paragraphs:
188+
189+# First
190+# Second:
191+#* Fee
192+#* Fie
193+#* Foe
194+
195+# Third
196+
197+h2. Tabs and spaces
198+
199+* this is a list item indented with tabs
200+* this is a list item indented with spaces
201+** this is an example list item indented with tabs
202+** this is an example list item indented with spaces
203+
204+
205+h2. Fancy list markers
206+
207+ <ol start="2" style="list-style-type: decimal;">
208+ <li>begins with 2</li>
209+ <li> <p>and now 3</p>
210+ <p>with a continuation</p>
211+ <ol start="4" style="list-style-type: lower-roman;">
212+ <li>sublist with roman numerals, starting with 4</li>
213+ <li>more items
214+ <ol style="list-style-type: upper-alpha;">
215+ <li>a subsublist</li>
216+ <li>a subsublist</li> </ol>
217+</li> </ol>
218+</li> </ol>
219+
220+Nesting:
221+
222+ <ol style="list-style-type: upper-alpha;">
223+ <li>Upper Alpha
224+ <ol style="list-style-type: upper-roman;">
225+ <li>Upper Roman.
226+ <ol start="6" style="list-style-type: decimal;">
227+ <li>Decimal start with 6
228+ <ol start="3" style="list-style-type: lower-alpha;">
229+ <li>Lower alpha with paren</li> </ol>
230+</li> </ol>
231+</li> </ol>
232+</li> </ol>
233+
234+Autonumbering:
235+
236+# Autonumber.
237+# More.
238+## Nested.
239+
240+
241+Should not be a list item:
242+
243+M.A. 2007
244+
245+B. Williams
246+
247+<hr />
248+
249+h1. Definition Lists
250+
251+Tight using spaces:
252+
253+ <dl>
254+ <dt>apple</dt>
255+ <dd>red fruit</dd>
256+ <dt>orange</dt>
257+ <dd>orange fruit</dd>
258+ <dt>banana</dt>
259+ <dd>yellow fruit</dd> </dl>
260+
261+Tight using tabs:
262+
263+ <dl>
264+ <dt>apple</dt>
265+ <dd>red fruit</dd>
266+ <dt>orange</dt>
267+ <dd>orange fruit</dd>
268+ <dt>banana</dt>
269+ <dd>yellow fruit</dd> </dl>
270+
271+Loose:
272+
273+ <dl>
274+ <dt>apple</dt>
275+ <dd> <p>red fruit</p></dd>
276+ <dt>orange</dt>
277+ <dd> <p>orange fruit</p></dd>
278+ <dt>banana</dt>
279+ <dd> <p>yellow fruit</p></dd> </dl>
280+
281+Multiple blocks with italics:
282+
283+ <dl>
284+ <dt>_apple_</dt>
285+ <dd> <p>red fruit</p>
286+ <p>contains seeds, crisp, pleasant to taste</p></dd>
287+ <dt>_orange_</dt>
288+ <dd> <p>orange fruit</p>
289+bc. { orange code block }
290+
291+bq. <p>orange block quote</p></dd> </dl>
292+
293+Multiple definitions, tight:
294+
295+ <dl>
296+ <dt>apple</dt>
297+ <dd>red fruit</dd>
298+ <dd>computer</dd>
299+ <dt>orange</dt>
300+ <dd>orange fruit</dd>
301+ <dd>bank</dd> </dl>
302+
303+Multiple definitions, loose:
304+
305+ <dl>
306+ <dt>apple</dt>
307+ <dd> <p>red fruit</p></dd>
308+ <dd> <p>computer</p></dd>
309+ <dt>orange</dt>
310+ <dd> <p>orange fruit</p></dd>
311+ <dd> <p>bank</p></dd> </dl>
312+
313+Blank line after term, indented marker, alternate markers:
314+
315+ <dl>
316+ <dt>apple</dt>
317+ <dd> <p>red fruit</p></dd>
318+ <dd> <p>computer</p></dd>
319+ <dt>orange</dt>
320+ <dd> <p>orange fruit</p>
321+ <ol style="list-style-type: decimal;">
322+ <li>sublist</li>
323+ <li>sublist</li> </ol>
324+</dd> </dl>
325+
326+h1. HTML Blocks
327+
328+Simple block on one line:
329+
330+<div>
331+foo
332+</div>
333+
334+And nested without indentation:
335+
336+<div>
337+<div>
338+<div>
339+foo
340+</div>
341+</div>
342+<div>
343+bar
344+</div>
345+</div>
346+
347+Interpreted markdown in a table:
348+
349+<table>
350+<tr>
351+<td>
352+This is _emphasized_
353+</td>
354+<td>
355+And this is *strong*
356+</td>
357+</tr>
358+</table>
359+
360+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
361+
362+Here's a simple block:
363+
364+<div>
365+
366+foo
367+</div>
368+
369+This should be a code block, though:
370+
371+bc. &lt;div&gt;
372+ foo
373+&lt;/div&gt;
374+
375+As should this:
376+
377+bc. &lt;div&gt;foo&lt;/div&gt;
378+
379+Now, nested:
380+
381+<div>
382+ <div>
383+ <div>
384+
385+foo
386+</div>
387+ </div>
388+</div>
389+
390+This should just be an HTML comment:
391+
392+<!-- Comment -->
393+
394+Multiline:
395+
396+<!--
397+Blah
398+Blah
399+-->
400+
401+<!--
402+ This is another comment.
403+-->
404+
405+Code block:
406+
407+bc. &lt;!-- Comment --&gt;
408+
409+Just plain comment, with trailing spaces on the line:
410+
411+<!-- foo -->
412+
413+Code:
414+
415+bc. &lt;hr /&gt;
416+
417+Hr's:
418+
419+<hr>
420+
421+<hr />
422+
423+<hr />
424+
425+<hr>
426+
427+<hr />
428+
429+<hr />
430+
431+<hr class="foo" id="bar" />
432+
433+<hr class="foo" id="bar" />
434+
435+<hr class="foo" id="bar">
436+
437+<hr />
438+
439+h1. Inline Markup
440+
441+This is _emphasized_, and so _is this_.
442+
443+This is *strong*, and so *is this*.
444+
445+An _"emphasized link":/url_.
446+
447+*_This is strong and em._*
448+
449+So is *_this_* word.
450+
451+*_This is strong and em._*
452+
453+So is *_this_* word.
454+
455+This is code: @&gt;@, @$@, @\@, @\$@, @&lt;html&gt;@.
456+
457+-This is _strikeout_.-
458+
459+Superscripts: a^bc^d a^_hello_^ a^hello there^.
460+
461+Subscripts: H~2~O, H~23~O, H~many of them~O.
462+
463+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
464+
465+<hr />
466+
467+h1. Smart quotes, ellipses, dashes
468+
469+"Hello," said the spider. "'Shelob' is my name."
470+
471+'A', 'B', and 'C' are letters.
472+
473+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
474+
475+'He said, "I want to go."' Were you alive in the 70's?
476+
477+Here is some quoted '@code@' and a ""quoted link":http://example.com/?foo=1&bar=2".
478+
479+Some dashes: one -- two -- three -- four -- five.
480+
481+Dashes between numbers: 5 - 7, 255 - 66, 1987 - 1999.
482+
483+Ellipses...and...and....
484+
485+<hr />
486+
487+h1. LaTeX
488+
489+*
490+* <span class="math">2+2=4</math>
491+* <span class="math">x \in y</math>
492+* <span class="math">\alpha \wedge \omega</math>
493+* <span class="math">223</math>
494+* <span class="math">p</math>-Tree
495+* Here's some display math: <span class="math">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
496+* Here's one that has a line break in it: <span class="math">\alpha + \omega \times x^2</math>.
497+
498+These shouldn't be math:
499+
500+* To get the famous equation, write @$e = mc^2$@.
501+* $22,000 is a _lot_ of money. So is $34,000. (It worked if "lot" is emphasized.)
502+* Shoes ($20) and socks ($5).
503+* Escaped @$@: $73 _this should be emphasized_ 23$.
504+
505+Here's a LaTeX table:
506+
507+
508+
509+<hr />
510+
511+h1. Special Characters
512+
513+Here is some unicode:
514+
515+* I hat: Î
516+* o umlaut: ö
517+* section: §
518+* set membership: ∈
519+* copyright: ©
520+
521+AT&amp;T has an ampersand in their name.
522+
523+AT&amp;T is another way to write it.
524+
525+This &amp; that.
526+
527+4 &lt; 5.
528+
529+6 &gt; 5.
530+
531+Backslash: \
532+
533+Backtick: `
534+
535+Asterisk: &#42;
536+
537+Underscore: &#95;
538+
539+Left brace: {
540+
541+Right brace: }
542+
543+Left bracket: [
544+
545+Right bracket: ]
546+
547+Left paren: (
548+
549+Right paren: )
550+
551+Greater-than: &gt;
552+
553+Hash: #
554+
555+Period: .
556+
557+Bang: !
558+
559+Plus: +
560+
561+Minus: -
562+
563+<hr />
564+
565+h1. Links
566+
567+h2. Explicit
568+
569+Just a "URL":/url/.
570+
571+"URL and title":/url/.
572+
573+"URL and title":/url/.
574+
575+"URL and title":/url/.
576+
577+"URL and title":/url/
578+
579+"URL and title":/url/
580+
581+"with&#95;underscore":/url/with_underscore
582+
583+"Email link":mailto:nobody@nowhere.net
584+
585+"Empty":.
586+
587+h2. Reference
588+
589+Foo "bar":/url/.
590+
591+Foo "bar":/url/.
592+
593+Foo "bar":/url/.
594+
595+With "embedded [brackets]":/url/.
596+
597+"b":/url/ by itself should be a link.
598+
599+Indented "once":/url.
600+
601+Indented "twice":/url.
602+
603+Indented "thrice":/url.
604+
605+This should [not][] be a link.
606+
607+bc. [not]: /url
608+
609+Foo "bar":/url/.
610+
611+Foo "biz":/url/.
612+
613+h2. With ampersands
614+
615+Here's a "link with an ampersand in the URL":http://example.com/?foo=1&bar=2.
616+
617+Here's a link with an amersand in the link text: "AT&amp;T":http://att.com/.
618+
619+Here's an "inline link":/script?foo=1&bar=2.
620+
621+Here's an "inline link in pointy braces":/script?foo=1&bar=2.
622+
623+h2. Autolinks
624+
625+With an ampersand: "http://example.com/?foo=1&bar=2":http://example.com/?foo=1&bar=2
626+
627+* In a list?
628+* "http://example.com/":http://example.com/
629+* It should.
630+
631+An e-mail address: "nobody@nowhere.net":mailto:nobody@nowhere.net
632+
633+bq. Blockquoted: "http://example.com/":http://example.com/
634+
635+Auto-links should not occur here: @&lt;http://example.com/&gt;@
636+
637+bc. or here: &lt;http://example.com/&gt;
638+
639+<hr />
640+
641+h1. Images
642+
643+From "Voyage dans la Lune" by Georges Melies (1902):
644+
645+!lalune.jpg(Voyage dans la Lune)!
646+lalune
647+
648+Here is a movie !movie.jpg(movie)! icon.
649+
650+<hr />
651+
652+h1. Footnotes
653+
654+Here is a footnote reference,[1] and another.[2] This should _not_ be a footnote reference, because it contains a space.[^my note] Here is an inline note.[3]
655+
656+bq. Notes can go in quotes.[4]
657+
658+# And in list items.[5]
659+
660+This paragraph should not be part of the note, as it is not indented.
661+
662+
663+fn1. Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
664+
665+
666+fn2. Here's the long note. This one contains multiple blocks.
667+
668+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
669+
670+bc. { &lt;code&gt; }
671+
672+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
673+
674+
675+fn3. This is _easier_ to type. Inline notes may contain "links":http://google.com and @]@ verbatim characters, as well as [bracketed text].
676+
677+
678+fn4. In quote.
679+
680+
681+fn5. In list.
682+
683+