git.iko.soy/typeable/pandoc
on master help sign in
Add section identifiers support for FB2 writer (#5315)
c75b558John
src/Text/Pandoc/Writers/FB2.hs+28−35
@@ -52,13 +52,15 @@ import Network.HTTP (urlEncode)
52import Text.XML.Light
52import Text.XML.Light
53import qualified Text.XML.Light as X
53import qualified Text.XML.Light as X
54import qualified Text.XML.Light.Cursor as XC
54import qualified Text.XML.Light.Cursor as XC
55+import qualified Text.XML.Light.Input as XI
55
56
56import Text.Pandoc.Class (PandocMonad, report)
57import Text.Pandoc.Class (PandocMonad, report)
57import qualified Text.Pandoc.Class as P
58import qualified Text.Pandoc.Class as P
58import Text.Pandoc.Definition
59import Text.Pandoc.Definition
59import Text.Pandoc.Logging
60import Text.Pandoc.Logging
60import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
61import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
61−import Text.Pandoc.Shared (capitalize, isHeaderBlock, isURI, orderedListMarkers)
62+import Text.Pandoc.Shared (capitalize, isURI, orderedListMarkers, hierarchicalize)
63+import qualified Text.Pandoc.Shared as Shared (Element(Blk, Sec))
62
64
63-- | Data to be written at the end of the document:
65-- | Data to be written at the end of the document:
64-- (foot)notes, URLs, references, images.
66-- (foot)notes, URLs, references, images.
@@ -177,20 +179,28 @@ docdate meta' = do
177-- representation.
179-- representation.
178renderSections :: PandocMonad m => Int -> [Block] -> FBM m [Content]
180renderSections :: PandocMonad m => Int -> [Block] -> FBM m [Content]
179renderSections level blocks = do
181renderSections level blocks = do
180− let secs = splitSections level blocks
182+ let elements = hierarchicalize blocks
183+ let isSection Shared.Sec{} = True
184+ isSection _ = False
185+ let (initialBlocks, secs) = break isSection elements
186+ let elements' = if null initialBlocks
187+ then secs
188+ else Shared.Sec 1 [] nullAttr mempty initialBlocks : secs
181− mapM (renderSection level) secs
189+ cMapM (renderSection level) elements'
182−
190+
191+
192+
183−renderSection :: PandocMonad m => Int -> ([Inline], [Block]) -> FBM m Content
193+renderSection :: PandocMonad m => Int -> Shared.Element -> FBM m [Content]
184−renderSection level (ttl, body) = do
194+renderSection _ (Shared.Blk block) = blockToXml block
195+renderSection lvl (Shared.Sec _ _num (id',_,_) title elements) = do
196+ content <- cMapM (renderSection (lvl + 1)) elements
185− title <- if null ttl
197+ title' <- if null title
186 then return []
198 then return []
187− else list . el "title" <$> formatTitle ttl
199+ else list . el "title" <$> formatTitle title
188− content <- if hasSubsections body
200+ let sectionContent = if null id'
189− then renderSections (level + 1) body
201+ then el "section" (title' ++ content)
190− else cMapM blockToXml body
202+ else el "section" ([uattr "id" id'], (title' ++ content))
191− return $ el "section" (title ++ content)
203+ return $ [sectionContent]
192− where
193− hasSubsections = any isHeaderBlock
194
204
195-- | Only <p> and <empty-line> are allowed within <title> in FB2.
205-- | Only <p> and <empty-line> are allowed within <title> in FB2.
196formatTitle :: PandocMonad m => [Inline] -> FBM m [Content]
206formatTitle :: PandocMonad m => [Inline] -> FBM m [Content]
@@ -206,24 +216,6 @@ isLineBreak :: Inline -> Bool
206isLineBreak LineBreak = True
216isLineBreak LineBreak = True
207isLineBreak _ = False
217isLineBreak _ = False
208
218
209−-- | Divide the stream of block elements into sections: [(title, blocks)].
210−splitSections :: Int -> [Block] -> [([Inline], [Block])]
211−splitSections level blocks = reverse $ revSplit (reverse blocks)
212− where
213− revSplit [] = []
214− revSplit rblocks =
215− let (lastsec, before) = break sameLevel rblocks
216− (header, prevblocks) =
217− case before of
218− (Header n _ title:prevblocks') ->
219− if n == level
220− then (title, prevblocks')
221− else ([], before)
222− _ -> ([], before)
223− in (header, reverse lastsec) : revSplit prevblocks
224− sameLevel (Header n _ _) = n == level
225− sameLevel _ = False
226−
227-- | Make another FictionBook body with footnotes.
219-- | Make another FictionBook body with footnotes.
228renderFootnotes :: PandocMonad m => FBM m [Content]
220renderFootnotes :: PandocMonad m => FBM m [Content]
229renderFootnotes = do
221renderFootnotes = do
@@ -325,9 +317,10 @@ blockToXml (Para [Image atr alt (src,'f':'i':'g':':':tit)]) =
325blockToXml (Para ss) = (list . el "p") <$> cMapM toXml ss
317blockToXml (Para ss) = (list . el "p") <$> cMapM toXml ss
326blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
318blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
327 map (el "p" . el "code") . lines $ s
319 map (el "p" . el "code") . lines $ s
328−blockToXml b@(RawBlock _ _) = do
320+blockToXml (RawBlock f str) = do
329− report $ BlockNotRendered b
321+ if f == Format "fb2"
322+ then return $ XI.parseXML str
330− return []
323+ else return []
331blockToXml (Div _ bs) = cMapM blockToXml bs
324blockToXml (Div _ bs) = cMapM blockToXml bs
332blockToXml (BlockQuote bs) = (list . el "cite") <$> cMapM blockToXml bs
325blockToXml (BlockQuote bs) = (list . el "cite") <$> cMapM blockToXml bs
333blockToXml (LineBlock lns) =
326blockToXml (LineBlock lns) =
test/fb2/basic.fb2+3−3
@@ -12,15 +12,15 @@
12<title>
12<title>
13<p />
13<p />
14</title>
14</title>
15−<section>
15+<section id="top-level-title">
16<title>
16<title>
17<p>Top-level title</p>
17<p>Top-level title</p>
18</title>
18</title>
19−<section>
19+<section id="section">
20<title>
20<title>
21<p>Section</p>
21<p>Section</p>
22</title>
22</title>
23−<section>
23+<section id="subsection">
24<title>
24<title>
25<p>Subsection</p>
25<p>Subsection</p>
26</title>
26</title>
test/fb2/titles.fb2+1−1
@@ -1,3 +1,3 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?xml version="1.0" encoding="UTF-8"?>
2−<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><title><p>Simple title</p></title><p>This example tests FictionBook titles.</p></section><section><title><p><emphasis>Emphasized</emphasis> <strong>Strong</strong> Title</p></title></section></body></FictionBook>
2+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section id="simple-title"><title><p>Simple title</p></title><p>This example tests FictionBook titles.</p></section><section id="emphasized-strong-title"><title><p><emphasis>Emphasized</emphasis> <strong>Strong</strong> Title</p></title></section></body></FictionBook>
3
3
test/writer.fb2+31−31
@@ -26,25 +26,25 @@
26John Gruber’s markdown test suite.</p>
26John Gruber’s markdown test suite.</p>
27<empty-line />
27<empty-line />
28</section>
28</section>
29−<section>
29+<section id="headers">
30<title>
30<title>
31<p>Headers</p>
31<p>Headers</p>
32</title>
32</title>
33−<section>
33+<section id="level-2-with-an-embedded-link">
34<title>
34<title>
35<p>Level 2 with an <a l:href="/url">embedded link</a>
35<p>Level 2 with an <a l:href="/url">embedded link</a>
36</p>
36</p>
37</title>
37</title>
38−<section>
38+<section id="level-3-with-emphasis">
39<title>
39<title>
40<p>Level 3 with <emphasis>emphasis</emphasis>
40<p>Level 3 with <emphasis>emphasis</emphasis>
41</p>
41</p>
42</title>
42</title>
43−<section>
43+<section id="level-4">
44<title>
44<title>
45<p>Level 4</p>
45<p>Level 4</p>
46</title>
46</title>
47−<section>
47+<section id="level-5">
48<title>
48<title>
49<p>Level 5</p>
49<p>Level 5</p>
50</title>
50</title>
@@ -53,23 +53,23 @@ John Gruber’s markdown test suite.</p>
53</section>
53</section>
54</section>
54</section>
55</section>
55</section>
56−<section>
56+<section id="level-1">
57<title>
57<title>
58<p>Level 1</p>
58<p>Level 1</p>
59</title>
59</title>
60−<section>
60+<section id="level-2-with-emphasis">
61<title>
61<title>
62<p>Level 2 with <emphasis>emphasis</emphasis>
62<p>Level 2 with <emphasis>emphasis</emphasis>
63</p>
63</p>
64</title>
64</title>
65−<section>
65+<section id="level-3">
66<title>
66<title>
67<p>Level 3</p>
67<p>Level 3</p>
68</title>
68</title>
69<p>with no blank line</p>
69<p>with no blank line</p>
70</section>
70</section>
71</section>
71</section>
72−<section>
72+<section id="level-2">
73<title>
73<title>
74<p>Level 2</p>
74<p>Level 2</p>
75</title>
75</title>
@@ -77,7 +77,7 @@ John Gruber’s markdown test suite.</p>
77<empty-line />
77<empty-line />
78</section>
78</section>
79</section>
79</section>
80−<section>
80+<section id="paragraphs">
81<title>
81<title>
82<p>Paragraphs</p>
82<p>Paragraphs</p>
83</title>
83</title>
@@ -93,7 +93,7 @@ list item.</p>
93here.</p>
93here.</p>
94<empty-line />
94<empty-line />
95</section>
95</section>
96−<section>
96+<section id="block-quotes">
97<title>
97<title>
98<p>Block Quotes</p>
98<p>Block Quotes</p>
99</title>
99</title>
@@ -131,7 +131,7 @@ It is pretty short.</p>
131<p>And a following paragraph.</p>
131<p>And a following paragraph.</p>
132<empty-line />
132<empty-line />
133</section>
133</section>
134−<section>
134+<section id="code-blocks">
135<title>
135<title>
136<p>Code Blocks</p>
136<p>Code Blocks</p>
137</title>
137</title>
@@ -176,11 +176,11 @@ It is pretty short.</p>
176<empty-line />
176<empty-line />
177<empty-line />
177<empty-line />
178</section>
178</section>
179−<section>
179+<section id="lists">
180<title>
180<title>
181<p>Lists</p>
181<p>Lists</p>
182</title>
182</title>
183−<section>
183+<section id="unordered">
184<title>
184<title>
185<p>Unordered</p>
185<p>Unordered</p>
186</title>
186</title>
@@ -218,7 +218,7 @@ It is pretty short.</p>
218<p>• Minus 3</p>
218<p>• Minus 3</p>
219<empty-line />
219<empty-line />
220</section>
220</section>
221−<section>
221+<section id="ordered">
222<title>
222<title>
223<p>Ordered</p>
223<p>Ordered</p>
224</title>
224</title>
@@ -255,7 +255,7 @@ back.</p>
255<p>3. Item 3.</p>
255<p>3. Item 3.</p>
256<empty-line />
256<empty-line />
257</section>
257</section>
258−<section>
258+<section id="nested">
259<title>
259<title>
260<p>Nested</p>
260<p>Nested</p>
261</title>
261</title>
@@ -280,7 +280,7 @@ back.</p>
280<p>3. Third</p>
280<p>3. Third</p>
281<empty-line />
281<empty-line />
282</section>
282</section>
283−<section>
283+<section id="tabs-and-spaces">
284<title>
284<title>
285<p>Tabs and spaces</p>
285<p>Tabs and spaces</p>
286</title>
286</title>
@@ -297,7 +297,7 @@ indented with tabs</p>
297indented with spaces</p>
297indented with spaces</p>
298<empty-line />
298<empty-line />
299</section>
299</section>
300−<section>
300+<section id="fancy-list-markers">
301<title>
301<title>
302<p>Fancy list markers</p>
302<p>Fancy list markers</p>
303</title>
303</title>
@@ -326,7 +326,7 @@ starting with 4</p>
326<empty-line />
326<empty-line />
327</section>
327</section>
328</section>
328</section>
329−<section>
329+<section id="definition-lists">
330<title>
330<title>
331<p>Definition Lists</p>
331<p>Definition Lists</p>
332</title>
332</title>
@@ -440,7 +440,7 @@ crisp, pleasant to taste</p>
440<p>1. sublist</p>
440<p>1. sublist</p>
441<p>2. sublist</p>
441<p>2. sublist</p>
442</section>
442</section>
443−<section>
443+<section id="html-blocks">
444<title>
444<title>
445<p>HTML Blocks</p>
445<p>HTML Blocks</p>
446</title>
446</title>
@@ -484,7 +484,7 @@ crisp, pleasant to taste</p>
484<p>Hr’s:</p>
484<p>Hr’s:</p>
485<empty-line />
485<empty-line />
486</section>
486</section>
487−<section>
487+<section id="inline-markup">
488<title>
488<title>
489<p>Inline Markup</p>
489<p>Inline Markup</p>
490</title>
490</title>
@@ -521,7 +521,7 @@ crisp, pleasant to taste</p>
521because of the unescaped spaces: a^b c^d, a~b c~d.</p>
521because of the unescaped spaces: a^b c^d, a~b c~d.</p>
522<empty-line />
522<empty-line />
523</section>
523</section>
524−<section>
524+<section id="smart-quotes-ellipses-dashes">
525<title>
525<title>
526<p>Smart quotes, ellipses, dashes</p>
526<p>Smart quotes, ellipses, dashes</p>
527</title>
527</title>
@@ -537,7 +537,7 @@ So is ‘pine.’</p>
537<p>Ellipses…and…and….</p>
537<p>Ellipses…and…and….</p>
538<empty-line />
538<empty-line />
539</section>
539</section>
540−<section>
540+<section id="latex">
541<title>
541<title>
542<p>LaTeX</p>
542<p>LaTeX</p>
543</title>
543</title>
@@ -564,7 +564,7 @@ So is ‘pine.’</p>
564<p>Here’s a LaTeX table:</p>
564<p>Here’s a LaTeX table:</p>
565<empty-line />
565<empty-line />
566</section>
566</section>
567−<section>
567+<section id="special-characters">
568<title>
568<title>
569<p>Special Characters</p>
569<p>Special Characters</p>
570</title>
570</title>
@@ -597,11 +597,11 @@ So is ‘pine.’</p>
597<p>Minus: -</p>
597<p>Minus: -</p>
598<empty-line />
598<empty-line />
599</section>
599</section>
600−<section>
600+<section id="links">
601<title>
601<title>
602<p>Links</p>
602<p>Links</p>
603</title>
603</title>
604−<section>
604+<section id="explicit">
605<title>
605<title>
606<p>Explicit</p>
606<p>Explicit</p>
607</title>
607</title>
@@ -627,7 +627,7 @@ So is ‘pine.’</p>
627<p>
627<p>
628<a l:href="">Empty</a>.</p>
628<a l:href="">Empty</a>.</p>
629</section>
629</section>
630−<section>
630+<section id="reference">
631<title>
631<title>
632<p>Reference</p>
632<p>Reference</p>
633</title>
633</title>
@@ -647,7 +647,7 @@ So is ‘pine.’</p>
647<p>Foo <a l:href="/url/">bar</a>.</p>
647<p>Foo <a l:href="/url/">bar</a>.</p>
648<p>Foo <a l:href="/url/">biz</a>.</p>
648<p>Foo <a l:href="/url/">biz</a>.</p>
649</section>
649</section>
650−<section>
650+<section id="with-ampersands">
651<title>
651<title>
652<p>With ampersands</p>
652<p>With ampersands</p>
653</title>
653</title>
@@ -656,7 +656,7 @@ So is ‘pine.’</p>
656<p>Here’s an <a l:href="/script?foo=1&amp;bar=2">inline link</a>.</p>
656<p>Here’s an <a l:href="/script?foo=1&amp;bar=2">inline link</a>.</p>
657<p>Here’s an <a l:href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
657<p>Here’s an <a l:href="/script?foo=1&amp;bar=2">inline link in pointy braces</a>.</p>
658</section>
658</section>
659−<section>
659+<section id="autolinks">
660<title>
660<title>
661<p>Autolinks</p>
661<p>Autolinks</p>
662</title>
662</title>
@@ -682,7 +682,7 @@ So is ‘pine.’</p>
682<empty-line />
682<empty-line />
683</section>
683</section>
684</section>
684</section>
685−<section>
685+<section id="images">
686<title>
686<title>
687<p>Images</p>
687<p>Images</p>
688</title>
688</title>
@@ -691,7 +691,7 @@ So is ‘pine.’</p>
691<p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p>
691<p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p>
692<empty-line />
692<empty-line />
693</section>
693</section>
694−<section>
694+<section id="footnotes">
695<title>
695<title>
696<p>Footnotes</p>
696<p>Footnotes</p>
697</title>
697</title>