git.iko.soy/typeable/pandoc
on master help sign in
Jira writer: use jira-wiki-markup renderer

Pandoc's AST is translated into the Jira AST, which is then rendered by the dedicated Jira printer. The following improvements are included in this change: - non-jira raw blocks are fully discarded instead of showing as blank lines; - table cells can contain multiple blocks; - unnecessary blank lines are removed from the output; - markup chars within words are properly surrounded by braces; - preserving soft linebreaks via `--wrap=preserve` is supported. Note that backslashes are rendered as HTML entities, as there appears no alternative to produce a plain backslash if it is followed by markup. This may cause problems when used with confluence, where rendering seems to fail in this case. Closes: #5926

commit2c13773be857357152750fd3c809326420caca31 authorAlbert Krewinkel <albert@zeitkraut.de> dateFri 20 Dec 2019, 17:12 (7 years ago) parentb06124e
3 files changed+286−412
src/Text/Pandoc/Writers/Jira.hs+222−266 test/tables.jira+18−23 test/writer.jira+46−123
src/Text/Pandoc/Writers/Jira.hs+222−266
@@ -1,3 +1,4 @@
1+{-# LANGUAGE LambdaCase #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE NoImplicitPrelude #-}
34{- |
@@ -16,296 +17,251 @@ JIRA:
1617-}
1718module Text.Pandoc.Writers.Jira ( writeJira ) where
1819import Prelude
19−import Control.Monad.State.Strict
20+import Control.Monad.Reader (ReaderT, ask, asks, runReaderT)
21+import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
2022import Data.Foldable (find)
21−import Data.Text (Text, pack)
22−import Text.Pandoc.Class (PandocMonad, report)
23+import Data.Text (Text)
24+import Text.Jira.Parser (plainText)
25+import Text.Jira.Printer (prettyBlocks, prettyInlines)
26+import Text.Pandoc.Class (PandocMonad)
2327import Text.Pandoc.Definition
24−import Text.Pandoc.Logging (LogMessage (BlockNotRendered, InlineNotRendered))
25−import Text.Pandoc.Options (WriterOptions (writerTemplate))
26−import Text.Pandoc.Shared (blocksToInlines, linesToPara)
28+import Text.Pandoc.Options (WriterOptions (writerTemplate, writerWrapText),
29+ WrapOption (..))
30+import Text.Pandoc.Shared (linesToPara)
2731import Text.Pandoc.Templates (renderTemplate)
2832import Text.Pandoc.Writers.Math (texMathToInlines)
29−import Text.Pandoc.Writers.Shared (metaToContext, defField)
30−import qualified Data.Text as T
33+import Text.Pandoc.Writers.Shared (defField, metaToContext)
3134import Text.DocLayout (literal, render)
35+import qualified Data.Text as T
36+import qualified Text.Jira.Markup as Jira
3237
33−data WriterState = WriterState
34− { stNotes :: [Text] -- Footnotes
35− , stListLevel :: Text -- String at beginning of list items, e.g. "**"
36− }
38+-- | Convert Pandoc to Jira.
39+writeJira :: PandocMonad m => WriterOptions -> Pandoc -> m Text
40+writeJira opts = runDefaultConverter (writerWrapText opts) (pandocToJira opts)
3741
38−-- | Initial writer state
39−startState :: WriterState
40−startState = WriterState
41− { stNotes = []
42− , stListLevel = ""
43− }
42+-- | State to keep track of footnotes.
43+newtype ConverterState = ConverterState { stNotes :: [Text] }
4444
45−type JiraWriter = StateT WriterState
45+-- | Initial converter state.
46+startState :: ConverterState
47+startState = ConverterState { stNotes = [] }
4648
47−-- | Convert Pandoc to Jira.
48−writeJira :: PandocMonad m => WriterOptions -> Pandoc -> m Text
49−writeJira opts document =
50− evalStateT (pandocToJira opts document) startState
49+-- | Converter monad
50+type JiraConverter m = ReaderT WrapOption (StateT ConverterState m)
51+
52+-- | Run a converter using the default state
53+runDefaultConverter :: PandocMonad m
54+ => WrapOption
55+ -> (a -> JiraConverter m Text)
56+ -> a
57+ -> m Text
58+runDefaultConverter wrap c x = evalStateT (runReaderT (c x) wrap) startState
5159
5260-- | Return Jira representation of document.
5361pandocToJira :: PandocMonad m
54− => WriterOptions -> Pandoc -> JiraWriter m Text
62+ => WriterOptions -> Pandoc -> JiraConverter m Text
5563pandocToJira opts (Pandoc meta blocks) = do
64+ wrap <- ask
5665 metadata <- metaToContext opts
57− (fmap literal . blockListToJira opts)
58− (fmap literal . inlineListToJira opts) meta
59− body <- blockListToJira opts blocks
66+ (fmap literal . runDefaultConverter wrap blockListToJira)
67+ (fmap literal . runDefaultConverter wrap inlineListToJira) meta
68+ body <- blockListToJira blocks
6069 notes <- gets $ T.intercalate "\n" . reverse . stNotes
61− let main = body <> if T.null notes
62− then mempty
63− else T.pack "\n\n" <> notes
70+ let main = body <> if T.null notes then mempty else "\n\n" <> notes
6471 let context = defField "body" main metadata
6572 return $
6673 case writerTemplate opts of
6774 Nothing -> main
6875 Just tpl -> render Nothing $ renderTemplate tpl context
6976
70−-- | Escape one character as needed for Jira.
71−escapeCharForJira :: Char -> Text
72−escapeCharForJira c =
73− let specialChars = "_*-+~^|!{}[]" :: String
74− in case c of
75− '\x2013' -> " -- "
76− '\x2014' -> " --- "
77− '\x2026' -> "..."
78− _ | c `elem` specialChars -> T.cons '\\' (T.singleton c)
79− _ -> T.singleton c
80−
81−-- | Escape string as needed for Jira.
82−escapeStringForJira :: Text -> Text
83−escapeStringForJira = T.concatMap escapeCharForJira
84−
85−-- | Create an anchor macro from the given element attributes.
86−anchor :: Attr -> Text
87−anchor (ident,_,_) =
88− if ident == ""
89− then ""
90− else "{anchor:" <> ident <> "}"
91−
92−-- | Append a newline character unless we are in a list.
93−appendNewlineUnlessInList :: PandocMonad m
94− => Text
95− -> JiraWriter m Text
96−appendNewlineUnlessInList t = do
97− listLevel <- gets stListLevel
98− return (if T.null listLevel then t <> "\n" else t)
99−
100−-- | Convert Pandoc block element to Jira.
101−blockToJira :: PandocMonad m
102− => WriterOptions -- ^ Options
103− -> Block -- ^ Block element
104− -> JiraWriter m Text
105−
106−blockToJira _ Null = return ""
107−
108−blockToJira opts (Div attr bs) =
109− (anchor attr <>) <$> blockListToJira opts bs
110−
111−blockToJira opts (Plain inlines) =
112− inlineListToJira opts inlines
113−
114−blockToJira opts (Para inlines) = do
115− contents <- inlineListToJira opts inlines
116− appendNewlineUnlessInList contents
117−
118−blockToJira opts (LineBlock lns) =
119− blockToJira opts $ linesToPara lns
120−
121−blockToJira _ b@(RawBlock f str) =
122− if f == Format "jira"
123− then return str
124− else "" <$ report (BlockNotRendered b)
125−
126−blockToJira _ HorizontalRule = return "----\n"
127−
128−blockToJira opts (Header level attr inlines) = do
129− contents <- inlineListToJira opts inlines
130− let prefix = "h" <> pack (show level) <> ". "
131− return $ prefix <> anchor attr <> contents <> "\n"
132−
133−blockToJira _ (CodeBlock attr@(_,classes,_) str) = do
134− let lang = find (\c -> T.toLower c `elem` knownLanguages) classes
135− let start = case lang of
136− Nothing -> "{code}"
137− Just l -> "{code:" <> l <> "}"
138− let anchorMacro = anchor attr
139− appendNewlineUnlessInList . T.intercalate "\n" $
140− (if anchorMacro == "" then id else (anchorMacro :))
141− [start, str, "{code}"]
142−
143−blockToJira opts (BlockQuote [p@(Para _)]) = do
144− contents <- blockToJira opts p
145− return ("bq. " <> contents)
146−
147−blockToJira opts (BlockQuote blocks) = do
148− contents <- blockListToJira opts blocks
149− appendNewlineUnlessInList . T.unlines $
150− [ "{quote}", contents, "{quote}"]
151−
152−blockToJira opts (Table _caption _aligns _widths headers rows) = do
153− headerCells <- mapM blocksToCell headers
154− bodyRows <- mapM (mapM blocksToCell) rows
155− let tblHead = headerCellsToRow headerCells
156− let tblBody = map cellsToRow bodyRows
157− return $ if all null headers
158− then T.unlines tblBody
159− else T.unlines (tblHead : tblBody)
160− where
161− blocksToCell :: PandocMonad m => [Block] -> JiraWriter m Text
162− blocksToCell = inlineListToJira opts . blocksToInlines
163−
164− cellsToRow :: [Text] -> Text
165− cellsToRow cells = "|" <> T.intercalate "|" cells <> "|"
166−
167− headerCellsToRow :: [Text] -> Text
168− headerCellsToRow cells = "||" <> T.intercalate "||" cells <> "||"
169−
170−blockToJira opts (BulletList items) =
171− listWithMarker opts items '*'
172−
173−blockToJira opts (OrderedList _listAttr items) =
174− listWithMarker opts items '#'
175−
176−blockToJira opts (DefinitionList items) =
177− blockToJira opts (BulletList (map defToBulletItem items))
178− where
179− defToBulletItem :: ([Inline], [[Block]]) -> [Block]
180− defToBulletItem (inlns, defs) =
181− let term = Plain [Strong inlns]
182− blks = mconcat defs
183− in term : blks
184−
185−-- Auxiliary functions for lists:
186−
187−-- | Create a list using the given character as bullet item marker.
188−listWithMarker :: PandocMonad m
189− => WriterOptions
190− -> [[Block]]
191− -> Char
192− -> JiraWriter m Text
193−listWithMarker opts items marker = do
194− modify $ \s -> s { stListLevel = stListLevel s `T.snoc` marker }
195− contents <- mapM (listItemToJira opts) items
196− modify $ \s -> s { stListLevel = T.init (stListLevel s) }
197− appendNewlineUnlessInList $ T.intercalate "\n" contents
198−
199−-- | Convert bullet or ordered list item (list of blocks) to Jira.
200−listItemToJira :: PandocMonad m
201− => WriterOptions
202− -> [Block]
203− -> JiraWriter m Text
204−listItemToJira opts items = do
205− contents <- blockListToJira opts items
206− marker <- gets stListLevel
207− return $ marker <> " " <> contents
208−
209−-- | Convert list of Pandoc block elements to Jira.
210−blockListToJira :: PandocMonad m
211− => WriterOptions -- ^ Options
212− -> [Block] -- ^ List of block elements
213− -> JiraWriter m Text
214−blockListToJira opts blocks =
215− T.intercalate "\n" <$> mapM (blockToJira opts) blocks
216−
217−-- | Convert list of Pandoc inline elements to Jira.
218−inlineListToJira :: PandocMonad m
219− => WriterOptions
220− -> [Inline]
221− -> JiraWriter m Text
222−inlineListToJira opts lst =
223− T.concat <$> mapM (inlineToJira opts) lst
224−
225−-- | Convert Pandoc inline element to Jira.
226−inlineToJira :: PandocMonad m
227− => WriterOptions
228− -> Inline
229− -> JiraWriter m Text
230−
231−inlineToJira opts (Span attr lst) =
232− (anchor attr <>) <$> inlineListToJira opts lst
233−
234−inlineToJira opts (Emph lst) = do
235− contents <- inlineListToJira opts lst
236− return $ "_" <> contents <> "_"
237−
238−inlineToJira opts (Strong lst) = do
239− contents <- inlineListToJira opts lst
240− return $ "*" <> contents <> "*"
241−
242−inlineToJira opts (Strikeout lst) = do
243− contents <- inlineListToJira opts lst
244− return $ "-" <> contents <> "-"
245−
246−inlineToJira opts (Superscript lst) = do
247− contents <- inlineListToJira opts lst
248− return $ "{^" <> contents <> "^}"
249−
250−inlineToJira opts (Subscript lst) = do
251− contents <- inlineListToJira opts lst
252− return $ "{~" <> contents <> "~}"
253−
254−inlineToJira opts (SmallCaps lst) = inlineListToJira opts lst
255−
256−inlineToJira opts (Quoted SingleQuote lst) = do
257− contents <- inlineListToJira opts lst
258− return $ "'" <> contents <> "'"
259−
260−inlineToJira opts (Quoted DoubleQuote lst) = do
261− contents <- inlineListToJira opts lst
262− return $ "\"" <> contents <> "\""
263−
264−inlineToJira opts (Cite _ lst) = inlineListToJira opts lst
265−
266−inlineToJira _ (Code attr str) =
267− return (anchor attr <> "{{" <> str <> "}}")
268−
269−inlineToJira _ (Str str) = return $ escapeStringForJira str
270−
271−inlineToJira opts (Math InlineMath str) =
272− lift (texMathToInlines InlineMath str) >>= inlineListToJira opts
273−
274−inlineToJira opts (Math DisplayMath str) = do
275− mathInlines <- lift (texMathToInlines DisplayMath str)
276− contents <- inlineListToJira opts mathInlines
277− return $ "\\\\" <> contents <> "\\\\"
278−
279−inlineToJira _opts il@(RawInline f str) =
280− if f == Format "jira"
281− then return str
282− else "" <$ report (InlineNotRendered il)
283−
284−inlineToJira _ LineBreak = return "\n"
285−
286−inlineToJira _ SoftBreak = return " "
287−
288−inlineToJira _ Space = return " "
289−
290−inlineToJira opts (Link _attr txt (src, _title)) = do
291− linkText <- inlineListToJira opts txt
292− return $ T.concat
293− [ "["
294− , if null txt then "" else linkText <> "|"
295− , src
296− , "]"
297− ]
298−
299−inlineToJira _opts (Image attr _alt (src, _title)) =
300− return . T.concat $ [anchor attr, "!", src, "!"]
301−
302−inlineToJira opts (Note contents) = do
77+blockListToJira :: PandocMonad m => [Block] -> JiraConverter m Text
78+blockListToJira = fmap prettyBlocks . toJiraBlocks
79+
80+inlineListToJira :: PandocMonad m => [Inline] -> JiraConverter m Text
81+inlineListToJira = fmap prettyInlines . toJiraInlines
82+
83+toJiraBlocks :: PandocMonad m => [Block] -> JiraConverter m [Jira.Block]
84+toJiraBlocks blocks = do
85+ let convert = \case
86+ BlockQuote bs -> singleton . Jira.BlockQuote
87+ <$> toJiraBlocks bs -- FIXME!
88+ BulletList items -> singleton . Jira.List Jira.CircleBullets
89+ <$> toJiraItems items
90+ CodeBlock attr cs -> toJiraCode attr cs
91+ DefinitionList items -> toJiraDefinitionList items
92+ Div attr bs -> toJiraPanel attr bs
93+ Header lvl attr xs -> toJiraHeader lvl attr xs
94+ HorizontalRule -> return . singleton $ Jira.HorizontalRule
95+ LineBlock xs -> toJiraBlocks [linesToPara xs]
96+ OrderedList _ items -> singleton . Jira.List Jira.Enumeration
97+ <$> toJiraItems items
98+ Para xs -> singleton . Jira.Para <$> toJiraInlines xs
99+ Plain xs -> singleton . Jira.Para <$> toJiraInlines xs
100+ RawBlock fmt cs -> rawBlockToJira fmt cs
101+ Null -> return mempty
102+ Table _ _ _ hd body -> singleton <$> do
103+ headerRow <- if null hd
104+ then Just <$> toRow Jira.HeaderCell hd
105+ else pure Nothing
106+ bodyRows <- mapM (toRow Jira.BodyCell) body
107+ let rows = case headerRow of
108+ Just header -> header : bodyRows
109+ Nothing -> bodyRows
110+ return $ Jira.Table rows
111+ jiraBlocks <- mapM convert blocks
112+ return $ mconcat jiraBlocks
113+
114+toRow :: PandocMonad m
115+ => ([Jira.Block] -> Jira.Cell)
116+ -> [TableCell]
117+ -> JiraConverter m Jira.Row
118+toRow mkCell cells = Jira.Row <$>
119+ mapM (fmap mkCell . toJiraBlocks) cells
120+
121+toJiraItems :: PandocMonad m => [[Block]] -> JiraConverter m [[Jira.Block]]
122+toJiraItems = mapM toJiraBlocks
123+
124+toJiraCode :: PandocMonad m
125+ => Attr
126+ -> Text
127+ -> JiraConverter m [Jira.Block]
128+toJiraCode (ident, classes, _attribs) code = do
129+ let lang = case find (\c -> T.toLower c `elem` knownLanguages) classes of
130+ Nothing -> Jira.Language "java"
131+ Just l -> Jira.Language l
132+ let addAnchor b = if T.null ident
133+ then b
134+ else [Jira.Para (singleton (Jira.Anchor ident))] <> b
135+ return . addAnchor . singleton $ Jira.Code lang mempty code
136+
137+-- | Creates a Jira definition list
138+toJiraDefinitionList :: PandocMonad m
139+ => [([Inline], [[Block]])]
140+ -> JiraConverter m [Jira.Block]
141+toJiraDefinitionList defItems = do
142+ let convertDefItem (term, defs) = do
143+ jiraTerm <- Jira.Para <$> styled Jira.Strong term
144+ jiraDefs <- mconcat <$> mapM toJiraBlocks defs
145+ return $ jiraTerm : jiraDefs
146+ singleton . Jira.List Jira.CircleBullets <$> mapM convertDefItem defItems
147+
148+-- | Creates a Jira panel
149+toJiraPanel :: PandocMonad m
150+ => Attr -> [Block]
151+ -> JiraConverter m [Jira.Block]
152+toJiraPanel attr blocks = do
153+ jiraBlocks <- toJiraBlocks blocks
154+ return $ if attr == nullAttr
155+ then jiraBlocks
156+ else singleton (Jira.Panel [] jiraBlocks)
157+
158+-- | Creates a Jira header
159+toJiraHeader :: PandocMonad m
160+ => Int -> Attr -> [Inline]
161+ -> JiraConverter m [Jira.Block]
162+toJiraHeader lvl (ident, _, _) inlines =
163+ let anchor = Jira.Anchor ident
164+ in singleton . Jira.Header lvl . (anchor :) <$> toJiraInlines inlines
165+
166+-- | Handles raw block. Jira is included verbatim, everything else is
167+-- discarded.
168+rawBlockToJira :: PandocMonad m
169+ => Format -> Text
170+ -> JiraConverter m [Jira.Block]
171+rawBlockToJira fmt cs = do
172+ rawInlines <- toJiraRaw fmt cs
173+ return $
174+ if null rawInlines
175+ then mempty
176+ else singleton (Jira.Para rawInlines)
177+
178+toJiraRaw :: PandocMonad m
179+ => Format -> Text -> JiraConverter m [Jira.Inline]
180+toJiraRaw fmt cs = case fmt of
181+ Format "jira" -> return . singleton $ Jira.Str cs
182+ _ -> return mempty
183+
184+
185+--
186+-- Inlines
187+--
188+
189+toJiraInlines :: PandocMonad m => [Inline] -> JiraConverter m [Jira.Inline]
190+toJiraInlines inlines = do
191+ let convert = \case
192+ Cite _ xs -> toJiraInlines xs
193+ Code _ cs -> return . singleton $
194+ Jira.Monospaced (escapeSpecialChars cs)
195+ Emph xs -> styled Jira.Emphasis xs
196+ Image _ _ (src, _) -> pure . singleton $ Jira.Image [] (Jira.URL src)
197+ LineBreak -> pure . singleton $ Jira.Linebreak
198+ Link _ xs (tgt, _) -> singleton . flip Jira.Link (Jira.URL tgt)
199+ <$> toJiraInlines xs
200+ Math mtype cs -> mathToJira mtype cs
201+ Note bs -> registerNotes bs
202+ Quoted qt xs -> quotedToJira qt xs
203+ RawInline fmt cs -> toJiraRaw fmt cs
204+ SmallCaps xs -> styled Jira.Strong xs
205+ SoftBreak -> do
206+ preserveBreak <- asks (== WrapPreserve)
207+ pure . singleton $ if preserveBreak
208+ then Jira.Linebreak
209+ else Jira.Space
210+ Space -> pure . singleton $ Jira.Space
211+ Span _attr xs -> toJiraInlines xs
212+ Str s -> pure $ escapeSpecialChars s
213+ Strikeout xs -> styled Jira.Strikeout xs
214+ Strong xs -> styled Jira.Strong xs
215+ Subscript xs -> styled Jira.Subscript xs
216+ Superscript xs -> styled Jira.Superscript xs
217+ jiraInlines <- mapM convert inlines
218+ return $ mconcat jiraInlines
219+
220+singleton :: a -> [a]
221+singleton = (:[])
222+
223+styled :: PandocMonad m
224+ => Jira.InlineStyle -> [Inline]
225+ -> JiraConverter m [Jira.Inline]
226+styled s = fmap (singleton . Jira.Styled s) . toJiraInlines
227+
228+-- | Converts a plain text value to Jira inlines, ensuring that all
229+-- special characters will be handled appropriately.
230+escapeSpecialChars :: Text -> [Jira.Inline]
231+escapeSpecialChars t = case plainText t of
232+ Right xs -> xs
233+ Left _ -> singleton $ Jira.Str t
234+
235+mathToJira :: PandocMonad m
236+ => MathType
237+ -> Text
238+ -> JiraConverter m [Jira.Inline]
239+mathToJira mtype cs = do
240+ mathInlines <- toJiraInlines =<< texMathToInlines mtype cs
241+ return $ case mtype of
242+ InlineMath -> mathInlines
243+ DisplayMath -> Jira.Linebreak : mathInlines ++ [Jira.Linebreak]
244+
245+quotedToJira :: PandocMonad m
246+ => QuoteType
247+ -> [Inline]
248+ -> JiraConverter m [Jira.Inline]
249+quotedToJira qtype xs = do
250+ let quoteChar = case qtype of
251+ DoubleQuote -> "\""
252+ SingleQuote -> "'"
253+ let surroundWithQuotes = (Jira.Str quoteChar :) . (++ [Jira.Str quoteChar])
254+ surroundWithQuotes <$> toJiraInlines xs
255+
256+registerNotes :: PandocMonad m => [Block] -> JiraConverter m [Jira.Inline]
257+registerNotes contents = do
303258 curNotes <- gets stNotes
304259 let newnum = length curNotes + 1
305− contents' <- blockListToJira opts contents
306− let thisnote = "[" <> pack (show newnum) <> "] " <> contents' <> "\n"
260+ contents' <- blockListToJira contents
261+ let thisnote = "\\[" <> T.pack (show newnum) <> "] " <> contents' <> "\n"
307262 modify $ \s -> s { stNotes = thisnote : curNotes }
308− return $ "[" <> pack (show newnum) <> "]"
263+ return . singleton . Jira.Str $
264+ "[" <> T.pack (show newnum) <> "]"
309265
310266-- | Language codes recognized by jira
311267knownLanguages :: [Text]
test/tables.jira+18−23
@@ -1,43 +1,38 @@
11Simple table with caption:
22
3−||Right||Left||Center||Default||
4−|12|12|12|12|
5−|123|123|123|123|
6−|1|1|1|1|
3+| 12 | 12 | 12 | 12 |
4+| 123 | 123 | 123 | 123 |
5+| 1 | 1 | 1 | 1 |
76
87Simple table without caption:
98
10−||Right||Left||Center||Default||
11−|12|12|12|12|
12−|123|123|123|123|
13−|1|1|1|1|
9+| 12 | 12 | 12 | 12 |
10+| 123 | 123 | 123 | 123 |
11+| 1 | 1 | 1 | 1 |
1412
1513Simple table indented two spaces:
1614
17−||Right||Left||Center||Default||
18−|12|12|12|12|
19−|123|123|123|123|
20−|1|1|1|1|
15+| 12 | 12 | 12 | 12 |
16+| 123 | 123 | 123 | 123 |
17+| 1 | 1 | 1 | 1 |
2118
2219Multiline table with caption:
2320
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.|
21+| First | row | 12.0 | Example of a row that spans multiple lines. |
22+| Second | row | 5.0 | Here’s another one. Note the blank line between rows. |
2723
2824Multiline table without caption:
2925
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.|
26+| First | row | 12.0 | Example of a row that spans multiple lines. |
27+| Second | row | 5.0 | Here’s another one. Note the blank line between rows. |
3328
3429Table without column headers:
3530
36−|12|12|12|12|
37−|123|123|123|123|
38−|1|1|1|1|
31+| 12 | 12 | 12 | 12 |
32+| 123 | 123 | 123 | 123 |
33+| 1 | 1 | 1 | 1 |
3934
4035Multiline table without column headers:
4136
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.|
37+| First | row | 12.0 | Example of a row that spans multiple lines. |
38+| Second | row | 5.0 | Here’s another one. Note the blank line between rows. |
test/writer.jira+46−123
@@ -1,59 +1,43 @@
11This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.
22
33----
4−
54h1. {anchor:headers}Headers
6−
75h2. {anchor:level-2-with-an-embedded-link}Level 2 with an [embedded link|/url]
8−
96h3. {anchor:level-3-with-emphasis}Level 3 with _emphasis_
10−
117h4. {anchor:level-4}Level 4
12−
138h5. {anchor:level-5}Level 5
14−
159h1. {anchor:level-1}Level 1
16−
1710h2. {anchor:level-2-with-emphasis}Level 2 with _emphasis_
18−
1911h3. {anchor:level-3}Level 3
20−
2112with no blank line
2213
2314h2. {anchor:level-2}Level 2
24−
2515with no blank line
2616
2717----
28−
2918h1. {anchor:paragraphs}Paragraphs
30−
3119Here’s a regular paragraph.
3220
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.
21+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.
3422
35−Here’s one with a bullet. \* criminey.
23+Here’s one with a bullet. * criminey.
3624
3725There should be a hard line break
3826here.
3927
4028----
41−
4229h1. {anchor:block-quotes}Block Quotes
43−
44−E\-mail style:
30+E-mail style:
4531
4632bq. This is a block quote. It is pretty short.
47−
4833{quote}
4934Code in a block quote:
5035
51−{code}
36+{code:java}
5237sub status {
5338 print "working";
5439}
5540{code}
56−
5741A list:
5842
5943# item one
@@ -62,23 +46,17 @@ A list:
6246Nested block quotes:
6347
6448bq. nested
65−
6649bq. nested
67−
6850{quote}
69−
70−
7151This should not be a block quote: 2 > 1.
7252
7353And a following paragraph.
7454
7555----
76−
7756h1. {anchor:code-blocks}Code Blocks
78−
7957Code:
8058
81−{code}
59+{code:java}
8260---- (should be four hyphens)
8361
8462sub status {
@@ -87,21 +65,16 @@ sub status {
8765
8866this code block is indented by one tab
8967{code}
90−
9168And:
9269
93−{code}
70+{code:java}
9471 this code block is indented by two tabs
9572
9673These should not be escaped: \$ \\ \> \[ \{
9774{code}
98−
9975----
100−
10176h1. {anchor:lists}Lists
102−
10377h2. {anchor:unordered}Unordered
104−
10578Asterisks tight:
10679
10780* asterisk 1
@@ -139,7 +112,6 @@ Minuses loose:
139112* Minus 3
140113
141114h2. {anchor:ordered}Ordered
142−
143115Tight:
144116
145117# First
@@ -172,7 +144,6 @@ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
172144# Item 3.
173145
174146h2. {anchor:nested}Nested
175−
176147* Tab
177148** Tab
178149*** Tab
@@ -196,14 +167,12 @@ Same thing but with paragraphs:
196167# Third
197168
198169h2. {anchor:tabs-and-spaces}Tabs and spaces
199−
200170* this is a list item indented with tabs
201171* this is a list item indented with spaces
202172** this is an example list item indented with tabs
203173** this is an example list item indented with spaces
204174
205175h2. {anchor:fancy-list-markers}Fancy list markers
206−
207176# begins with 2
208177# and now 3
209178with a continuation
@@ -232,9 +201,7 @@ M.A. 2007
232201B. Williams
233202
234203----
235−
236204h1. {anchor:definition-lists}Definition Lists
237−
238205Tight using spaces:
239206
240207* *apple*
@@ -269,7 +236,7 @@ red fruit
269236contains seeds, crisp, pleasant to taste
270237* *_orange_*
271238orange fruit
272−{code}
239+{code:java}
273240{ orange code block }
274241{code}
275242bq. orange block quote
@@ -303,86 +270,62 @@ orange fruit
303270*# sublist
304271
305272h1. {anchor:html-blocks}HTML Blocks
306−
307273Simple block on one line:
308274
309275foo
276+
310277And nested without indentation:
311278
312279foo
313280
314281bar
315−Interpreted markdown in a table:
316−
317−
318282
283+Interpreted markdown in a table:
319284
320285This is _emphasized_
321286
322−
323287And this is *strong*
324288
325−
326−
327−
328289Here’s a simple block:
329290
330291foo
331292
332293This should be a code block, though:
333294
334−{code}
295+{code:java}
335296<div>
336297 foo
337298</div>
338299{code}
339−
340300As should this:
341301
342−{code}
302+{code:java}
343303<div>foo</div>
344304{code}
345−
346305Now, nested:
347306
348307foo
349−This should just be an HTML comment:
350308
309+This should just be an HTML comment:
351310
352311Multiline:
353312
354−
355−
356313Code block:
357314
358−{code}
315+{code:java}
359316<!-- Comment -->
360317{code}
361−
362318Just plain comment, with trailing spaces on the line:
363319
364−
365320Code:
366321
367−{code}
322+{code:java}
368323<hr />
369324{code}
370−
371325Hr’s:
372326
373−
374−
375−
376−
377−
378−
379−
380−
381−
382327----
383−
384328h1. {anchor:inline-markup}Inline Markup
385−
386329This is _emphasized_, and so _is this_.
387330
388331This is *strong*, and so *is this*.
@@ -397,20 +340,18 @@ So is *_this_* word.
397340
398341So is *_this_* word.
399342
400−This is code: {{>}}, {{$}}, {{\}}, {{\$}}, {{<html>}}.
343+This is code: {{>}}, {{$}}, {{&bsol;}}, {{&bsol;$}}, {{<html>}}.
401344
402345-This is _strikeout_.-
403346
404−Superscripts: a{^bc^}d a{^_hello_^} a{^hello there^}.
347+Superscripts: a{^}bc{^}d a{^}_hello_{^} a{^}hello there{^}.
405348
406−Subscripts: H{~2~}O, H{~23~}O, H{~many of them~}O.
349+Subscripts: H{~}2{~}O, H{~}23{~}O, H{~}many of them{~}O.
407350
408−These should not be superscripts or subscripts, because of the unescaped spaces: a\^b c\^d, a\~b c\~d.
351+These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
409352
410353----
411−
412354h1. {anchor:smart-quotes-ellipses-dashes}Smart quotes, ellipses, dashes
413−
414355"Hello," said the spider. "'Shelob' is my name."
415356
416357'A', 'B', and 'C' are letters.
@@ -421,39 +362,36 @@ h1. {anchor:smart-quotes-ellipses-dashes}Smart quotes, ellipses, dashes
421362
422363Here is some quoted '{{code}}' and a "[quoted link|http://example.com/?foo=1&bar=2]".
423364
424−Some dashes: one --- two --- three --- four --- five.
365+Some dashes: one—two — three—four — five.
425366
426−Dashes between numbers: 5 -- 7, 255 -- 66, 1987 -- 1999.
367+Dashes between numbers: 5–7, 255–66, 1987–1999.
427368
428−Ellipses...and...and....
369+Ellipses…and…and….
429370
430371----
431−
432372h1. {anchor:latex}LaTeX
433−
434373*
435−* 2 \+ 2 = 4
436−* _x_ ∈ _y_
437−* _α_ ∧ _ω_
374+* 2 + 2 = 4
375+* _x_ ∈ {_}y{_}
376+* _α_ ∧ {_}ω{_}
438377* 223
439378* _p_\-Tree
440−* Here’s some display math: \\$$\frac\{d\}\{dx\}f(x)=\lim\_\{h\to 0\}\frac\{f(x\+h)\-f(x)\}\{h\}$$\\
441−* Here’s one that has a line break in it: _α_ \+ _ω_ × _x_{^2^}.
379+* Here’s some display math:
380+$$\frac{d\}\{dx}f\(x)=\lim\_\{h\to 0\}&bsol;frac{f(x+h)-f\(x)\}\{h}$$
381+
382+* Here’s one that has a line break in it: _α_ + {_}ω{_} × {_}x{_}^2^.
442383
443384These shouldn’t be math:
444385
445386* To get the famous equation, write {{$e = mc^2$}}.
446−* $22,000 is a _lot_ of money. So is $34,000. (It worked if "lot" is emphasized.)
447−* Shoes ($20) and socks ($5).
387+* $22,000 is a _lot_ of money. So is $34,000. \(It worked if "lot" is emphasized.)
388+* Shoes \($20) and socks \($5).
448389* Escaped {{$}}: $73 _this should be emphasized_ 23$.
449390
450391Here’s a LaTeX table:
451392
452−
453393----
454−
455394h1. {anchor:special-characters}Special Characters
456−
457395Here is some unicode:
458396
459397* I hat: Î
@@ -472,7 +410,7 @@ This & that.
472410
4734116 > 5.
474412
475−Backslash: \
413+Backslash: &bsol;
476414
477415Backtick: `
478416
@@ -488,11 +426,11 @@ Left bracket: \[
488426
489427Right bracket: \]
490428
491−Left paren: (
429+Left paren: \(
492430
493431Right paren: )
494432
495−Greater\-than: >
433+Greater-than: >
496434
497435Hash: #
498436
@@ -505,11 +443,8 @@ Plus: \+
505443Minus: \-
506444
507445----
508−
509446h1. {anchor:links}Links
510−
511447h2. {anchor:explicit}Explicit
512−
513448Just a [URL|/url/].
514449
515450[URL and title|/url/].
@@ -522,14 +457,13 @@ Just a [URL|/url/].
522457
523458[URL and title|/url/]
524459
525−[with\_underscore|/url/with_underscore]
460+[with_underscore|/url/with_underscore]
526461
527462[Email link|mailto:nobody@nowhere.net]
528463
529464[Empty|].
530465
531466h2. {anchor:reference}Reference
532−
533467Foo [bar|/url/].
534468
535469With [embedded \[brackets\]|/url/].
@@ -544,16 +478,14 @@ Indented [thrice|/url].
544478
545479This should \[not\]\[\] be a link.
546480
547−{code}
481+{code:java}
548482[not]: /url
549483{code}
550−
551484Foo [bar|/url/].
552485
553486Foo [biz|/url/].
554487
555488h2. {anchor:with-ampersands}With ampersands
556−
557489Here’s a [link with an ampersand in the URL|http://example.com/?foo=1&bar=2].
558490
559491Here’s a link with an amersand in the link text: [AT&T|http://att.com/].
@@ -563,64 +495,55 @@ Here’s an [inline link|/script?foo=1&bar=2].
563495Here’s an [inline link in pointy braces|/script?foo=1&bar=2].
564496
565497h2. {anchor:autolinks}Autolinks
566−
567498With an ampersand: [http://example.com/?foo=1&bar=2|http://example.com/?foo=1&bar=2]
568499
569500* In a list?
570501* [http://example.com/|http://example.com/]
571502* It should.
572503
573−An e\-mail address: [nobody@nowhere.net|mailto:nobody@nowhere.net]
504+An e-mail address: [nobody@nowhere.net|mailto:nobody@nowhere.net]
574505
575506bq. Blockquoted: [http://example.com/|http://example.com/]
507+Auto-links should not occur here: {{<http://example.com/>}}
576508
577−Auto\-links should not occur here: {{<http://example.com/>}}
578−
579−{code}
509+{code:java}
580510or here: <http://example.com/>
581511{code}
582−
583512----
584−
585513h1. {anchor:images}Images
586−
587−From "Voyage dans la Lune" by Georges Melies (1902):
514+From "Voyage dans la Lune" by Georges Melies \(1902):
588515
589516!lalune.jpg!
590517
591518Here is a movie !movie.jpg! icon.
592519
593520----
594−
595521h1. {anchor:footnotes}Footnotes
596−
597522Here 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]
598523
599524bq. Notes can go in quotes.[4]
600−
601525# And in list items.[5]
602526
603527This paragraph should not be part of the note, as it is not indented.
604528
605529
606−[1] Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
530+\[1] Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.
607531
608532
609−[2] Here’s the long note. This one contains multiple blocks.
533+\[2] Here’s the long note. This one contains multiple blocks.
610534
611−Subsequent blocks are indented to show that they belong to the footnote (as with list items).
535+Subsequent blocks are indented to show that they belong to the footnote \(as with list items).
612536
613−{code}
537+{code:java}
614538 { <code> }
615539{code}
616−
617540If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
618541
619542
620−[3] This is _easier_ to type. Inline notes may contain [links|http://google.com] and {{]}} verbatim characters, as well as \[bracketed text\].
543+\[3] This is _easier_ to type. Inline notes may contain [links|http://google.com] and {{\]}} verbatim characters, as well as \[bracketed text].
621544
622545
623−[4] In quote.
546+\[4] In quote.
624547
625548
626−[5] In list.
549+\[5] In list.