git.iko.soy/typeable/pandoc
on master help sign in
Add jira writer (#5548)

This adds support for Atlassian's jira markup. Closes #2497

commit1c368574651c7584439290181564e5d449e894b3 authorAlbert Krewinkel <albert@zeitkraut.de> dateWed 5 Jun 2019, 23:52 (7 years ago) parent62f8422
7 files changed+1015
data/templates/default.jira+9 pandoc.cabal+4 src/Text/Pandoc/Writers.hs+3 src/Text/Pandoc/Writers/Jira.hs+322 test/Tests/Old.hs+3 test/tables.jira+44 test/writer.jira+630
data/templates/default.jiranew file+9
@@ -0,0 +1,9 @@
1+$for(include-before)$
2+$include-before$
3+
4+$endfor$
5+$body$
6+$for(include-after)$
7+
8+$include-after$
9+$endfor$
pandoc.cabal+4
@@ -53,6 +53,7 @@ data-files:
5353 data/templates/default.latex
5454 data/templates/default.context
5555 data/templates/default.texinfo
56+ data/templates/default.jira
5657 data/templates/default.man
5758 data/templates/default.ms
5859 data/templates/default.markdown
@@ -242,6 +243,7 @@ extra-source-files:
242243 test/tables.docbook4
243244 test/tables.docbook5
244245 test/tables.jats
246+ test/tables.jira
245247 test/tables.dokuwiki
246248 test/tables.zimwiki
247249 test/tables.icml
@@ -273,6 +275,7 @@ extra-source-files:
273275 test/writer.docbook4
274276 test/writer.docbook5
275277 test/writer.jats
278+ test/writer.jira
276279 test/writer.html4
277280 test/writer.html5
278281 test/writer.man
@@ -500,6 +503,7 @@ library
500503 Text.Pandoc.Writers.HTML,
501504 Text.Pandoc.Writers.Ipynb,
502505 Text.Pandoc.Writers.ICML,
506+ Text.Pandoc.Writers.Jira,
503507 Text.Pandoc.Writers.LaTeX,
504508 Text.Pandoc.Writers.ConTeXt,
505509 Text.Pandoc.Writers.OpenDocument,
src/Text/Pandoc/Writers.hs+3
@@ -41,6 +41,7 @@ module Text.Pandoc.Writers
4141 , writeICML
4242 , writeJATS
4343 , writeJSON
44+ , writeJira
4445 , writeLaTeX
4546 , writeMan
4647 , writeMarkdown
@@ -91,6 +92,7 @@ import Text.Pandoc.Writers.Haddock
9192import Text.Pandoc.Writers.HTML
9293import Text.Pandoc.Writers.ICML
9394import Text.Pandoc.Writers.JATS
95+import Text.Pandoc.Writers.Jira
9496import Text.Pandoc.Writers.LaTeX
9597import Text.Pandoc.Writers.Man
9698import Text.Pandoc.Writers.Markdown
@@ -141,6 +143,7 @@ writers = [
141143 ,("docbook4" , TextWriter writeDocbook4)
142144 ,("docbook5" , TextWriter writeDocbook5)
143145 ,("jats" , TextWriter writeJATS)
146+ ,("jira" , TextWriter writeJira)
144147 ,("opml" , TextWriter writeOPML)
145148 ,("opendocument" , TextWriter writeOpenDocument)
146149 ,("latex" , TextWriter writeLaTeX)
src/Text/Pandoc/Writers/Jira.hsnew file+322
@@ -0,0 +1,322 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{- |
4+ Module : Text.Pandoc.Writers.Jira
5+ Copyright : © 2010-2019 Albert Krewinkel, John MacFarlane
6+ License : GNU GPL, version 2 or above
7+
8+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
9+ Stability : alpha
10+ Portability : portable
11+
12+Conversion of 'Pandoc' documents to Jira markup.
13+
14+JIRA:
15+<https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all>
16+-}
17+module Text.Pandoc.Writers.Jira ( writeJira ) where
18+import Prelude
19+import Control.Monad.State.Strict
20+import Data.Char (toLower)
21+import Data.Foldable (find)
22+import Data.Text (Text, pack)
23+import Text.Pandoc.Class (PandocMonad, report)
24+import Text.Pandoc.Definition
25+import Text.Pandoc.Logging (LogMessage (BlockNotRendered, InlineNotRendered))
26+import Text.Pandoc.Options (WriterOptions (writerTemplate))
27+import Text.Pandoc.Shared (blocksToInlines, linesToPara)
28+import Text.Pandoc.Templates (renderTemplate')
29+import Text.Pandoc.Writers.Math (texMathToInlines)
30+import Text.Pandoc.Writers.Shared (metaToJSON, defField)
31+import qualified Data.Text as T
32+
33+data WriterState = WriterState
34+ { stNotes :: [Text] -- Footnotes
35+ , stListLevel :: Text -- String at beginning of list items, e.g. "**"
36+ }
37+
38+-- | Initial writer state
39+startState :: WriterState
40+startState = WriterState
41+ { stNotes = []
42+ , stListLevel = ""
43+ }
44+
45+type JiraWriter = StateT WriterState
46+
47+-- | Convert Pandoc to Jira.
48+writeJira :: PandocMonad m => WriterOptions -> Pandoc -> m Text
49+writeJira opts document =
50+ evalStateT (pandocToJira opts document) startState
51+
52+-- | Return Jira representation of document.
53+pandocToJira :: PandocMonad m
54+ => WriterOptions -> Pandoc -> JiraWriter m Text
55+pandocToJira opts (Pandoc meta blocks) = do
56+ metadata <- metaToJSON opts (blockListToJira opts)
57+ (inlineListToJira opts) meta
58+ body <- blockListToJira opts blocks
59+ notes <- gets $ T.intercalate "\n" . reverse . stNotes
60+ let main = body <> if T.null notes then "" else "\n\n" <> notes
61+ let context = defField "body" main metadata
62+ case writerTemplate opts of
63+ Nothing -> return main
64+ Just tpl -> renderTemplate' tpl context
65+
66+-- | Escape one character as needed for Jira.
67+escapeCharForJira :: Char -> Text
68+escapeCharForJira c = case c of
69+ '&' -> "&amp;"
70+ '<' -> "&lt;"
71+ '>' -> "&gt;"
72+ '"' -> "&quot;"
73+ '*' -> "&ast;"
74+ '_' -> "&lowbar;"
75+ '@' -> "&commat;"
76+ '+' -> "&plus;"
77+ '-' -> "&hyphen;"
78+ '|' -> "&vert;"
79+ '{' -> "\\{"
80+ '\x2014' -> " -- "
81+ '\x2013' -> " - "
82+ '\x2019' -> "'"
83+ '\x2026' -> "..."
84+ _ -> T.singleton c
85+
86+-- | Escape string as needed for Jira.
87+escapeStringForJira :: Text -> Text
88+escapeStringForJira = T.concatMap escapeCharForJira
89+
90+-- | Create an anchor macro from the given element attributes.
91+anchor :: Attr -> Text
92+anchor (ident,_,_) =
93+ if ident == ""
94+ then ""
95+ else "{anchor:" <> pack ident <> "}"
96+
97+-- | Append a newline character unless we are in a list.
98+appendNewlineUnlessInList :: PandocMonad m
99+ => Text
100+ -> JiraWriter m Text
101+appendNewlineUnlessInList t = do
102+ listLevel <- gets stListLevel
103+ return (if T.null listLevel then t <> "\n" else t)
104+
105+-- | Convert Pandoc block element to Jira.
106+blockToJira :: PandocMonad m
107+ => WriterOptions -- ^ Options
108+ -> Block -- ^ Block element
109+ -> JiraWriter m Text
110+
111+blockToJira _ Null = return ""
112+
113+blockToJira opts (Div attr bs) =
114+ (anchor attr <>) <$> blockListToJira opts bs
115+
116+blockToJira opts (Plain inlines) =
117+ inlineListToJira opts inlines
118+
119+blockToJira opts (Para inlines) = do
120+ contents <- inlineListToJira opts inlines
121+ appendNewlineUnlessInList contents
122+
123+blockToJira opts (LineBlock lns) =
124+ blockToJira opts $ linesToPara lns
125+
126+blockToJira _ b@(RawBlock f str) =
127+ if f == Format "jira"
128+ then return (pack str)
129+ else "" <$ report (BlockNotRendered b)
130+
131+blockToJira _ HorizontalRule = return "----\n"
132+
133+blockToJira opts (Header level attr inlines) = do
134+ contents <- inlineListToJira opts inlines
135+ let prefix = "h" <> pack (show level) <> ". "
136+ return $ prefix <> anchor attr <> contents <> "\n"
137+
138+blockToJira _ (CodeBlock attr@(_,classes,_) str) = do
139+ let lang = find (\c -> map toLower c `elem` knownLanguages) classes
140+ let start = case lang of
141+ Nothing -> "{code}"
142+ Just l -> "{code:" <> pack l <> "}"
143+ let anchorMacro = anchor attr
144+ appendNewlineUnlessInList . T.intercalate "\n" $
145+ (if anchorMacro == "" then id else (anchorMacro :))
146+ [start, escapeStringForJira (pack str), "{code}"]
147+
148+blockToJira opts (BlockQuote [p@(Para _)]) = do
149+ contents <- blockToJira opts p
150+ appendNewlineUnlessInList ("bq. " <> contents)
151+
152+blockToJira opts (BlockQuote blocks) = do
153+ contents <- blockListToJira opts blocks
154+ appendNewlineUnlessInList . T.intercalate "\n" $
155+ [ "{quote}", contents, "{quote}"]
156+
157+blockToJira opts (Table _caption _aligns _widths headers rows) = do
158+ headerCells <- mapM blocksToCell headers
159+ bodyRows <- mapM (mapM blocksToCell) rows
160+ let tblHead = headerCellsToRow headerCells
161+ let tblBody = map cellsToRow bodyRows
162+ return $ if all null headers
163+ then T.unlines tblBody
164+ else T.unlines (tblHead : tblBody)
165+ where
166+ blocksToCell :: PandocMonad m => [Block] -> JiraWriter m Text
167+ blocksToCell = inlineListToJira opts . blocksToInlines
168+
169+ cellsToRow :: [Text] -> Text
170+ cellsToRow cells = "|" <> T.intercalate "|" cells <> "|"
171+
172+ headerCellsToRow :: [Text] -> Text
173+ headerCellsToRow cells = "||" <> T.intercalate "||" cells <> "||"
174+
175+blockToJira opts (BulletList items) =
176+ listWithMarker opts items '*'
177+
178+blockToJira opts (OrderedList _listAttr items) =
179+ listWithMarker opts items '#'
180+
181+blockToJira opts (DefinitionList items) =
182+ blockToJira opts (BulletList (map defToBulletItem items))
183+ where
184+ defToBulletItem :: ([Inline], [[Block]]) -> [Block]
185+ defToBulletItem (inlns, defs) =
186+ let term = Plain [Strong inlns]
187+ blks = mconcat defs
188+ in term : blks
189+
190+-- Auxiliary functions for lists:
191+
192+-- | Create a list using the given character as bullet item marker.
193+listWithMarker :: PandocMonad m
194+ => WriterOptions
195+ -> [[Block]]
196+ -> Char
197+ -> JiraWriter m Text
198+listWithMarker opts items marker = do
199+ modify $ \s -> s { stListLevel = stListLevel s `T.snoc` marker }
200+ contents <- mapM (listItemToJira opts) items
201+ modify $ \s -> s { stListLevel = T.init (stListLevel s) }
202+ appendNewlineUnlessInList $ T.intercalate "\n" contents
203+
204+-- | Convert bullet or ordered list item (list of blocks) to Jira.
205+listItemToJira :: PandocMonad m
206+ => WriterOptions
207+ -> [Block]
208+ -> JiraWriter m Text
209+listItemToJira opts items = do
210+ contents <- blockListToJira opts items
211+ marker <- gets stListLevel
212+ return $ marker <> " " <> contents
213+
214+-- | Convert list of Pandoc block elements to Jira.
215+blockListToJira :: PandocMonad m
216+ => WriterOptions -- ^ Options
217+ -> [Block] -- ^ List of block elements
218+ -> JiraWriter m Text
219+blockListToJira opts blocks =
220+ T.intercalate "\n" <$> mapM (blockToJira opts) blocks
221+
222+-- | Convert list of Pandoc inline elements to Jira.
223+inlineListToJira :: PandocMonad m
224+ => WriterOptions
225+ -> [Inline]
226+ -> JiraWriter m Text
227+inlineListToJira opts lst =
228+ T.concat <$> mapM (inlineToJira opts) lst
229+
230+-- | Convert Pandoc inline element to Jira.
231+inlineToJira :: PandocMonad m
232+ => WriterOptions
233+ -> Inline
234+ -> JiraWriter m Text
235+
236+inlineToJira opts (Span attr lst) =
237+ (anchor attr <>) <$> inlineListToJira opts lst
238+
239+inlineToJira opts (Emph lst) = do
240+ contents <- inlineListToJira opts lst
241+ return $ "_" <> contents <> "_"
242+
243+inlineToJira opts (Strong lst) = do
244+ contents <- inlineListToJira opts lst
245+ return $ "*" <> contents <> "*"
246+
247+inlineToJira opts (Strikeout lst) = do
248+ contents <- inlineListToJira opts lst
249+ return $ "-" <> contents <> "-"
250+
251+inlineToJira opts (Superscript lst) = do
252+ contents <- inlineListToJira opts lst
253+ return $ "{^" <> contents <> "^}"
254+
255+inlineToJira opts (Subscript lst) = do
256+ contents <- inlineListToJira opts lst
257+ return $ "{~" <> contents <> "~}"
258+
259+inlineToJira opts (SmallCaps lst) = inlineListToJira opts lst
260+
261+inlineToJira opts (Quoted SingleQuote lst) = do
262+ contents <- inlineListToJira opts lst
263+ return $ "'" <> contents <> "'"
264+
265+inlineToJira opts (Quoted DoubleQuote lst) = do
266+ contents <- inlineListToJira opts lst
267+ return $ "\"" <> contents <> "\""
268+
269+inlineToJira opts (Cite _ lst) = inlineListToJira opts lst
270+
271+inlineToJira _ (Code attr str) =
272+ return (anchor attr <> "{{" <> escapeStringForJira (pack str) <> "}}")
273+
274+inlineToJira _ (Str str) = return $ escapeStringForJira (pack str)
275+
276+inlineToJira opts (Math InlineMath str) =
277+ lift (texMathToInlines InlineMath str) >>= inlineListToJira opts
278+
279+inlineToJira opts (Math DisplayMath str) = do
280+ mathInlines <- lift (texMathToInlines DisplayMath str)
281+ contents <- inlineListToJira opts mathInlines
282+ return $ "\\\\" <> contents <> "\\\\"
283+
284+inlineToJira _opts il@(RawInline f str) =
285+ if f == Format "jira"
286+ then return (pack str)
287+ else "" <$ report (InlineNotRendered il)
288+
289+inlineToJira _ LineBreak = return "\n"
290+
291+inlineToJira _ SoftBreak = return " "
292+
293+inlineToJira _ Space = return " "
294+
295+inlineToJira opts (Link _attr txt (src, _title)) = do
296+ linkText <- inlineListToJira opts txt
297+ return $ T.concat
298+ [ "["
299+ , if null txt then "" else linkText <> "|"
300+ , pack src
301+ , "]"
302+ ]
303+
304+inlineToJira _opts (Image attr _alt (src, _title)) =
305+ return . T.concat $ [anchor attr, "!", pack src, "!"]
306+
307+inlineToJira opts (Note contents) = do
308+ curNotes <- gets stNotes
309+ let newnum = length curNotes + 1
310+ contents' <- blockListToJira opts contents
311+ let thisnote = "[" <> pack (show newnum) <> "] " <> contents' <> "\n"
312+ modify $ \s -> s { stNotes = thisnote : curNotes }
313+ return $ "[" <> pack (show newnum) <> "]"
314+
315+-- | Language codes recognized by jira
316+knownLanguages :: [String]
317+knownLanguages =
318+ [ "actionscript", "ada", "applescript", "bash", "c", "c#", "c++"
319+ , "css", "erlang", "go", "groovy", "haskell", "html", "javascript"
320+ , "json", "lua", "nyan", "objc", "perl", "php", "python", "r", "ruby"
321+ , "scala", "sql", "swift", "visualbasic", "xml", "yaml"
322+ ]
test/Tests/Old.hs+3
@@ -96,6 +96,9 @@ tests pandocPath =
9696 , test' "reader" ["-r", "jats", "-w", "native", "-s"]
9797 "jats-reader.xml" "jats-reader.native"
9898 ]
99+ , testGroup "jira"
100+ [ testGroup "writer" $ writerTests' "jira"
101+ ]
99102 , testGroup "native"
100103 [ testGroup "writer" $ writerTests' "native"
101104 , test' "reader" ["-r", "native", "-w", "native", "-s"]
test/tables.jiranew file+44
@@ -0,0 +1,44 @@
1+Simple table with caption:
2+
3+||Right||Left||Center||Default||
4+|12|12|12|12|
5+|123|123|123|123|
6+|1|1|1|1|
7+
8+Simple table without caption:
9+
10+||Right||Left||Center||Default||
11+|12|12|12|12|
12+|123|123|123|123|
13+|1|1|1|1|
14+
15+Simple table indented two spaces:
16+
17+||Right||Left||Center||Default||
18+|12|12|12|12|
19+|123|123|123|123|
20+|1|1|1|1|
21+
22+Multiline table with caption:
23+
24+||Centered Header||Left Aligned||Right Aligned||Default aligned||
25+|First|row|12.0|Example of a row that spans multiple lines.|
26+|Second|row|5.0|Here's another one. Note the blank line between rows.|
27+
28+Multiline table without caption:
29+
30+||Centered Header||Left Aligned||Right Aligned||Default aligned||
31+|First|row|12.0|Example of a row that spans multiple lines.|
32+|Second|row|5.0|Here's another one. Note the blank line between rows.|
33+
34+Table without column headers:
35+
36+|12|12|12|12|
37+|123|123|123|123|
38+|1|1|1|1|
39+
40+Multiline table without column headers:
41+
42+|First|row|12.0|Example of a row that spans multiple lines.|
43+|Second|row|5.0|Here's another one. Note the blank line between rows.|
44+
test/writer.jiranew file+630
@@ -0,0 +1,630 @@
1+This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
2+
3+----
4+
5+h1. {anchor:headers}Headers
6+
7+h2. {anchor:level-2-with-an-embedded-link}Level 2 with an [embedded link|/url]
8+
9+h3. {anchor:level-3-with-emphasis}Level 3 with _emphasis_
10+
11+h4. {anchor:level-4}Level 4
12+
13+h5. {anchor:level-5}Level 5
14+
15+h1. {anchor:level-1}Level 1
16+
17+h2. {anchor:level-2-with-emphasis}Level 2 with _emphasis_
18+
19+h3. {anchor:level-3}Level 3
20+
21+with no blank line
22+
23+h2. {anchor:level-2}Level 2
24+
25+with no blank line
26+
27+----
28+
29+h1. {anchor:paragraphs}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&hyphen;wrapped line in the middle of a paragraph looked like a list item.
34+
35+Here's one with a bullet. &ast; criminey.
36+
37+There should be a hard line break
38+here.
39+
40+----
41+
42+h1. {anchor:block-quotes}Block Quotes
43+
44+E&hyphen;mail style:
45+
46+bq. This is a block quote. It is pretty short.
47+
48+
49+{quote}
50+Code in a block quote:
51+
52+{code}
53+sub status \{
54+ print &quot;working&quot;;
55+}
56+{code}
57+
58+A list:
59+
60+# item one
61+# item two
62+
63+Nested block quotes:
64+
65+bq. nested
66+
67+
68+bq. nested
69+
70+
71+{quote}
72+
73+This should not be a block quote: 2 &gt; 1.
74+
75+And a following paragraph.
76+
77+----
78+
79+h1. {anchor:code-blocks}Code Blocks
80+
81+Code:
82+
83+{code}
84+&hyphen;&hyphen;&hyphen;&hyphen; (should be four hyphens)
85+
86+sub status \{
87+ print &quot;working&quot;;
88+}
89+
90+this code block is indented by one tab
91+{code}
92+
93+And:
94+
95+{code}
96+ this code block is indented by two tabs
97+
98+These should not be escaped: \$ \\ \&gt; \[ \\{
99+{code}
100+
101+----
102+
103+h1. {anchor:lists}Lists
104+
105+h2. {anchor:unordered}Unordered
106+
107+Asterisks tight:
108+
109+* asterisk 1
110+* asterisk 2
111+* asterisk 3
112+
113+Asterisks loose:
114+
115+* asterisk 1
116+* asterisk 2
117+* asterisk 3
118+
119+Pluses tight:
120+
121+* Plus 1
122+* Plus 2
123+* Plus 3
124+
125+Pluses loose:
126+
127+* Plus 1
128+* Plus 2
129+* Plus 3
130+
131+Minuses tight:
132+
133+* Minus 1
134+* Minus 2
135+* Minus 3
136+
137+Minuses loose:
138+
139+* Minus 1
140+* Minus 2
141+* Minus 3
142+
143+h2. {anchor:ordered}Ordered
144+
145+Tight:
146+
147+# First
148+# Second
149+# Third
150+
151+and:
152+
153+# One
154+# Two
155+# Three
156+
157+Loose using tabs:
158+
159+# First
160+# Second
161+# Third
162+
163+and using spaces:
164+
165+# One
166+# Two
167+# Three
168+
169+Multiple paragraphs:
170+
171+# Item 1, graf one.
172+Item 1. graf two. The quick brown fox jumped over the lazy dog's back.
173+# Item 2.
174+# Item 3.
175+
176+h2. {anchor:nested}Nested
177+
178+* Tab
179+** Tab
180+*** Tab
181+
182+Here's another:
183+
184+# First
185+# Second:
186+#* Fee
187+#* Fie
188+#* Foe
189+# Third
190+
191+Same thing but with paragraphs:
192+
193+# First
194+# Second:
195+#* Fee
196+#* Fie
197+#* Foe
198+# Third
199+
200+h2. {anchor:tabs-and-spaces}Tabs and spaces
201+
202+* this is a list item indented with tabs
203+* this is a list item indented with spaces
204+** this is an example list item indented with tabs
205+** this is an example list item indented with spaces
206+
207+h2. {anchor:fancy-list-markers}Fancy list markers
208+
209+# begins with 2
210+# and now 3
211+with a continuation
212+## sublist with roman numerals, starting with 4
213+## more items
214+### a subsublist
215+### a subsublist
216+
217+Nesting:
218+
219+# Upper Alpha
220+## Upper Roman.
221+### Decimal start with 6
222+#### Lower alpha with paren
223+
224+Autonumbering:
225+
226+# Autonumber.
227+# More.
228+## Nested.
229+
230+Should not be a list item:
231+
232+M.A. 2007
233+
234+B. Williams
235+
236+----
237+
238+h1. {anchor:definition-lists}Definition Lists
239+
240+Tight using spaces:
241+
242+* *apple*
243+red fruit
244+* *orange*
245+orange fruit
246+* *banana*
247+yellow fruit
248+
249+Tight using tabs:
250+
251+* *apple*
252+red fruit
253+* *orange*
254+orange fruit
255+* *banana*
256+yellow fruit
257+
258+Loose:
259+
260+* *apple*
261+red fruit
262+* *orange*
263+orange fruit
264+* *banana*
265+yellow fruit
266+
267+Multiple blocks with italics:
268+
269+* *_apple_*
270+red fruit
271+contains seeds, crisp, pleasant to taste
272+* *_orange_*
273+orange fruit
274+{code}
275+\{ orange code block }
276+{code}
277+bq. orange block quote
278+
279+Multiple definitions, tight:
280+
281+* *apple*
282+red fruit
283+computer
284+* *orange*
285+orange fruit
286+bank
287+
288+Multiple definitions, loose:
289+
290+* *apple*
291+red fruit
292+computer
293+* *orange*
294+orange fruit
295+bank
296+
297+Blank line after term, indented marker, alternate markers:
298+
299+* *apple*
300+red fruit
301+computer
302+* *orange*
303+orange fruit
304+*# sublist
305+*# sublist
306+
307+h1. {anchor:html-blocks}HTML Blocks
308+
309+Simple block on one line:
310+
311+foo
312+And nested without indentation:
313+
314+foo
315+
316+bar
317+Interpreted markdown in a table:
318+
319+
320+
321+
322+This is _emphasized_
323+
324+
325+And this is *strong*
326+
327+
328+
329+
330+Here's a simple block:
331+
332+foo
333+
334+This should be a code block, though:
335+
336+{code}
337+&lt;div&gt;
338+ foo
339+&lt;/div&gt;
340+{code}
341+
342+As should this:
343+
344+{code}
345+&lt;div&gt;foo&lt;/div&gt;
346+{code}
347+
348+Now, nested:
349+
350+foo
351+This should just be an HTML comment:
352+
353+
354+Multiline:
355+
356+
357+
358+Code block:
359+
360+{code}
361+&lt;!&hyphen;&hyphen; Comment &hyphen;&hyphen;&gt;
362+{code}
363+
364+Just plain comment, with trailing spaces on the line:
365+
366+
367+Code:
368+
369+{code}
370+&lt;hr /&gt;
371+{code}
372+
373+Hr's:
374+
375+
376+
377+
378+
379+
380+
381+
382+
383+
384+----
385+
386+h1. {anchor:inline-markup}Inline Markup
387+
388+This is _emphasized_, and so _is this_.
389+
390+This is *strong*, and so *is this*.
391+
392+An _[emphasized link|/url]_.
393+
394+*_This is strong and em._*
395+
396+So is *_this_* word.
397+
398+*_This is strong and em._*
399+
400+So is *_this_* word.
401+
402+This is code: {{&gt;}}, {{$}}, {{\}}, {{\$}}, {{&lt;html&gt;}}.
403+
404+-This is _strikeout_.-
405+
406+Superscripts: a{^bc^}d a{^_hello_^} a{^hello there^}.
407+
408+Subscripts: H{~2~}O, H{~23~}O, H{~many of them~}O.
409+
410+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
411+
412+----
413+
414+h1. {anchor:smart-quotes-ellipses-dashes}Smart quotes, ellipses, dashes
415+
416+"Hello," said the spider. "'Shelob' is my name."
417+
418+'A', 'B', and 'C' are letters.
419+
420+'Oak,' 'elm,' and 'beech' are names of trees. So is 'pine.'
421+
422+'He said, "I want to go."' Were you alive in the 70's?
423+
424+Here is some quoted '{{code}}' and a "[quoted link|http://example.com/?foo=1&bar=2]".
425+
426+Some dashes: one -- two -- three -- four -- five.
427+
428+Dashes between numbers: 5 - 7, 255 - 66, 1987 - 1999.
429+
430+Ellipses...and...and....
431+
432+----
433+
434+h1. {anchor:latex}LaTeX
435+
436+*
437+* 2 &plus; 2 = 4
438+* _x_ ∈ _y_
439+* _α_ ∧ _ω_
440+* 223
441+* _p_&hyphen;Tree
442+* Here's some display math: \\$$\frac\{d}\{dx}f(x)=\lim&lowbar;\{h\to 0}\frac\{f(x&plus;h)&hyphen;f(x)}\{h}$$\\
443+* Here's one that has a line break in it: _α_ &plus; _ω_ × _x_{^2^}.
444+
445+These shouldn't be math:
446+
447+* To get the famous equation, write {{$e = mc^2$}}.
448+* $22,000 is a _lot_ of money. So is $34,000. (It worked if "lot" is emphasized.)
449+* Shoes ($20) and socks ($5).
450+* Escaped {{$}}: $73 _this should be emphasized_ 23$.
451+
452+Here's a LaTeX table:
453+
454+
455+----
456+
457+h1. {anchor:special-characters}Special Characters
458+
459+Here is some unicode:
460+
461+* I hat: Î
462+* o umlaut: ö
463+* section: §
464+* set membership: ∈
465+* copyright: ©
466+
467+AT&amp;T has an ampersand in their name.
468+
469+AT&amp;T is another way to write it.
470+
471+This &amp; that.
472+
473+4 &lt; 5.
474+
475+6 &gt; 5.
476+
477+Backslash: \
478+
479+Backtick: `
480+
481+Asterisk: &ast;
482+
483+Underscore: &lowbar;
484+
485+Left brace: \{
486+
487+Right brace: }
488+
489+Left bracket: [
490+
491+Right bracket: ]
492+
493+Left paren: (
494+
495+Right paren: )
496+
497+Greater&hyphen;than: &gt;
498+
499+Hash: #
500+
501+Period: .
502+
503+Bang: !
504+
505+Plus: &plus;
506+
507+Minus: &hyphen;
508+
509+----
510+
511+h1. {anchor:links}Links
512+
513+h2. {anchor:explicit}Explicit
514+
515+Just a [URL|/url/].
516+
517+[URL and title|/url/].
518+
519+[URL and title|/url/].
520+
521+[URL and title|/url/].
522+
523+[URL and title|/url/]
524+
525+[URL and title|/url/]
526+
527+[with&lowbar;underscore|/url/with_underscore]
528+
529+[Email link|mailto:nobody@nowhere.net]
530+
531+[Empty|].
532+
533+h2. {anchor:reference}Reference
534+
535+Foo [bar|/url/].
536+
537+With [embedded [brackets]|/url/].
538+
539+[b|/url/] by itself should be a link.
540+
541+Indented [once|/url].
542+
543+Indented [twice|/url].
544+
545+Indented [thrice|/url].
546+
547+This should [not][] be a link.
548+
549+{code}
550+[not]: /url
551+{code}
552+
553+Foo [bar|/url/].
554+
555+Foo [biz|/url/].
556+
557+h2. {anchor:with-ampersands}With ampersands
558+
559+Here's a [link with an ampersand in the URL|http://example.com/?foo=1&bar=2].
560+
561+Here's a link with an amersand in the link text: [AT&amp;T|http://att.com/].
562+
563+Here's an [inline link|/script?foo=1&bar=2].
564+
565+Here's an [inline link in pointy braces|/script?foo=1&bar=2].
566+
567+h2. {anchor:autolinks}Autolinks
568+
569+With an ampersand: [http://example.com/?foo=1&amp;bar=2|http://example.com/?foo=1&bar=2]
570+
571+* In a list?
572+* [http://example.com/|http://example.com/]
573+* It should.
574+
575+An e&hyphen;mail address: [nobody&commat;nowhere.net|mailto:nobody@nowhere.net]
576+
577+bq. Blockquoted: [http://example.com/|http://example.com/]
578+
579+
580+Auto&hyphen;links should not occur here: {{&lt;http://example.com/&gt;}}
581+
582+{code}
583+or here: &lt;http://example.com/&gt;
584+{code}
585+
586+----
587+
588+h1. {anchor:images}Images
589+
590+From "Voyage dans la Lune" by Georges Melies (1902):
591+
592+!lalune.jpg!
593+
594+Here is a movie !movie.jpg! icon.
595+
596+----
597+
598+h1. {anchor:footnotes}Footnotes
599+
600+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]
601+
602+bq. Notes can go in quotes.[4]
603+
604+
605+# And in list items.[5]
606+
607+This paragraph should not be part of the note, as it is not indented.
608+
609+
610+[1] Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
611+
612+
613+[2] Here's the long note. This one contains multiple blocks.
614+
615+Subsequent blocks are indented to show that they belong to the footnote (as with list items).
616+
617+{code}
618+ \{ &lt;code&gt; }
619+{code}
620+
621+If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
622+
623+
624+[3] This is _easier_ to type. Inline notes may contain [links|http://google.com] and {{]}} verbatim characters, as well as [bracketed text].
625+
626+
627+[4] In quote.
628+
629+
630+[5] In list.