git.iko.soy/typeable/pandoc
on master help sign in
Merge pull request #2079 from lierdakil/rst-normalize-headings
44fcc5fJohn MacFarlane
pandoc.cabal+1
@@ -495,6 +495,7 @@ Test-Suite test-pandoc
495 Tests.Writers.AsciiDoc
495 Tests.Writers.AsciiDoc
496 Tests.Writers.LaTeX
496 Tests.Writers.LaTeX
497 Tests.Writers.Docx
497 Tests.Writers.Docx
498+ Tests.Writers.RST
498 Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
499 Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
499 Default-Language: Haskell98
500 Default-Language: Haskell98
500
501
src/Text/Pandoc/Writers/RST.hs+36−7
@@ -54,6 +54,7 @@ data WriterState =
54 , stHasMath :: Bool
54 , stHasMath :: Bool
55 , stHasRawTeX :: Bool
55 , stHasRawTeX :: Bool
56 , stOptions :: WriterOptions
56 , stOptions :: WriterOptions
57+ , stTopLevel :: Bool
57 }
58 }
58
59
59-- | Convert Pandoc to RST.
60-- | Convert Pandoc to RST.
@@ -61,7 +62,8 @@ writeRST :: WriterOptions -> Pandoc -> String
61writeRST opts document =
62writeRST opts document =
62 let st = WriterState { stNotes = [], stLinks = [],
63 let st = WriterState { stNotes = [], stLinks = [],
63 stImages = [], stHasMath = False,
64 stImages = [], stHasMath = False,
64− stHasRawTeX = False, stOptions = opts }
65+ stHasRawTeX = False, stOptions = opts,
66+ stTopLevel = True}
65 in evalState (pandocToRST document) st
67 in evalState (pandocToRST document) st
66
68
67-- | Return RST representation of document.
69-- | Return RST representation of document.
@@ -79,7 +81,7 @@ pandocToRST (Pandoc meta blocks) = do
79 (fmap (render colwidth) . blockListToRST)
81 (fmap (render colwidth) . blockListToRST)
80 (fmap (trimr . render colwidth) . inlineListToRST)
82 (fmap (trimr . render colwidth) . inlineListToRST)
81 $ deleteMeta "title" $ deleteMeta "subtitle" meta
83 $ deleteMeta "title" $ deleteMeta "subtitle" meta
82− body <- blockListToRST blocks
84+ body <- blockListToRST' True $ normalizeHeadings 1 blocks
83 notes <- liftM (reverse . stNotes) get >>= notesToRST
85 notes <- liftM (reverse . stNotes) get >>= notesToRST
84 -- note that the notes may contain refs, so we do them first
86 -- note that the notes may contain refs, so we do them first
85 refs <- liftM (reverse . stLinks) get >>= refsToRST
87 refs <- liftM (reverse . stLinks) get >>= refsToRST
@@ -98,6 +100,13 @@ pandocToRST (Pandoc meta blocks) = do
98 if writerStandalone opts
100 if writerStandalone opts
99 then return $ renderTemplate' (writerTemplate opts) context
101 then return $ renderTemplate' (writerTemplate opts) context
100 else return main
102 else return main
103+ where
104+ normalizeHeadings lev (Header l a i:bs) = Header lev a i:normalizeHeadings (lev+1) cont ++ normalizeHeadings lev bs'
105+ where (cont,bs') = break (headerLtEq l) bs
106+ headerLtEq level (Header l' _ _) = l' <= level
107+ headerLtEq _ _ = False
108+ normalizeHeadings lev (b:bs) = b:normalizeHeadings lev bs
109+ normalizeHeadings _ [] = []
101
110
102-- | Return RST representation of reference key table.
111-- | Return RST representation of reference key table.
103refsToRST :: Refs -> State WriterState Doc
112refsToRST :: Refs -> State WriterState Doc
@@ -191,11 +200,21 @@ blockToRST (RawBlock f@(Format f') str)
191 (nest 3 $ text str) $$ blankline
200 (nest 3 $ text str) $$ blankline
192blockToRST HorizontalRule =
201blockToRST HorizontalRule =
193 return $ blankline $$ "--------------" $$ blankline
202 return $ blankline $$ "--------------" $$ blankline
194−blockToRST (Header level _ inlines) = do
203+blockToRST (Header level (name,classes,_) inlines) = do
195 contents <- inlineListToRST inlines
204 contents <- inlineListToRST inlines
205+ isTopLevel <- gets stTopLevel
206+ if isTopLevel
207+ then do
196− let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
208+ let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
197− let border = text $ replicate (offset contents) headerChar
209+ let border = text $ replicate (offset contents) headerChar
198− return $ nowrap $ contents $$ border $$ blankline
210+ return $ nowrap $ contents $$ border $$ blankline
211+ else do
212+ let rub = "rubric:: " <> contents
213+ let name' | null name = empty
214+ | otherwise = ":name: " <> text name
215+ let cls | null classes = empty
216+ | otherwise = ":class: " <> text (unwords classes)
217+ return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
199blockToRST (CodeBlock (_,classes,kvs) str) = do
218blockToRST (CodeBlock (_,classes,kvs) str) = do
200 opts <- stOptions <$> get
219 opts <- stOptions <$> get
201 let tabstop = writerTabStop opts
220 let tabstop = writerTabStop opts
@@ -297,9 +316,19 @@ definitionListItemToRST (label, defs) = do
297 return $ label' $$ nest tabstop (nestle contents <> cr)
316 return $ label' $$ nest tabstop (nestle contents <> cr)
298
317
299-- | Convert list of Pandoc block elements to RST.
318-- | Convert list of Pandoc block elements to RST.
319+blockListToRST' :: Bool
320+ -> [Block] -- ^ List of block elements
321+ -> State WriterState Doc
322+blockListToRST' topLevel blocks = do
323+ tl <- gets stTopLevel
324+ modify (\s->s{stTopLevel=topLevel})
325+ res <- vcat `fmap` mapM blockToRST blocks
326+ modify (\s->s{stTopLevel=tl})
327+ return res
328+
300blockListToRST :: [Block] -- ^ List of block elements
329blockListToRST :: [Block] -- ^ List of block elements
301 -> State WriterState Doc
330 -> State WriterState Doc
302−blockListToRST blocks = mapM blockToRST blocks >>= return . vcat
331+blockListToRST = blockListToRST' False
303
332
304-- | Convert list of Pandoc inline elements to RST.
333-- | Convert list of Pandoc inline elements to RST.
305inlineListToRST :: [Inline] -> State WriterState Doc
334inlineListToRST :: [Inline] -> State WriterState Doc
tests/Tests/Writers/RST.hsnew file+79
@@ -0,0 +1,79 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.RST (tests) where
3+
4+import Test.Framework
5+import Text.Pandoc.Builder
6+import Text.Pandoc
7+import Tests.Helpers
8+import Tests.Arbitrary()
9+
10+infix 4 =:
11+(=:) :: (ToString a, ToPandoc a)
12+ => String -> (a, String) -> Test
13+(=:) = test (writeRST def{ writerHighlight = True } . toPandoc)
14+
15+tests :: [Test]
16+tests = [ testGroup "rubrics"
17+ [ "in list item" =:
18+ bulletList [header 2 (text "foo")] =?>
19+ "- .. rubric:: foo"
20+ , "in definition list item" =:
21+ definitionList [(text "foo", [header 2 (text "bar"),
22+ para $ text "baz"])] =?>
23+ unlines
24+ [ "foo"
25+ , " .. rubric:: bar"
26+ , ""
27+ , " baz"]
28+ , "in block quote" =:
29+ blockQuote (header 1 (text "bar")) =?>
30+ " .. rubric:: bar"
31+ , "with id" =:
32+ blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?>
33+ unlines
34+ [ " .. rubric:: bar"
35+ , " :name: foo"]
36+ , "with id class" =:
37+ blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?>
38+ unlines
39+ [ " .. rubric:: bar"
40+ , " :name: foo"
41+ , " :class: baz"]
42+ ]
43+ , testGroup "headings"
44+ [ "normal heading" =:
45+ header 1 (text "foo") =?>
46+ unlines
47+ [ "foo"
48+ , "==="]
49+ , "heading levels" =:
50+ header 1 (text "Header 1") <>
51+ header 3 (text "Header 2") <>
52+ header 2 (text "Header 2") <>
53+ header 1 (text "Header 1") <>
54+ header 4 (text "Header 2") <>
55+ header 5 (text "Header 3") <>
56+ header 3 (text "Header 2") =?>
57+ unlines
58+ [ "Header 1"
59+ , "========"
60+ , ""
61+ , "Header 2"
62+ , "--------"
63+ , ""
64+ , "Header 2"
65+ , "--------"
66+ , ""
67+ , "Header 1"
68+ , "========"
69+ , ""
70+ , "Header 2"
71+ , "--------"
72+ , ""
73+ , "Header 3"
74+ , "~~~~~~~~"
75+ , ""
76+ , "Header 2"
77+ , "--------"]
78+ ]
79+ ]
tests/test-pandoc.hs+2
@@ -21,6 +21,7 @@ import qualified Tests.Writers.Markdown
21import qualified Tests.Writers.Plain
21import qualified Tests.Writers.Plain
22import qualified Tests.Writers.AsciiDoc
22import qualified Tests.Writers.AsciiDoc
23import qualified Tests.Writers.Docx
23import qualified Tests.Writers.Docx
24+import qualified Tests.Writers.RST
24import qualified Tests.Shared
25import qualified Tests.Shared
25import qualified Tests.Walk
26import qualified Tests.Walk
26import Text.Pandoc.Shared (inDirectory)
27import Text.Pandoc.Shared (inDirectory)
@@ -40,6 +41,7 @@ tests = [ testGroup "Old" Tests.Old.tests
40 , testGroup "Plain" Tests.Writers.Plain.tests
41 , testGroup "Plain" Tests.Writers.Plain.tests
41 , testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests
42 , testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests
42 , testGroup "Docx" Tests.Writers.Docx.tests
43 , testGroup "Docx" Tests.Writers.Docx.tests
44+ , testGroup "RST" Tests.Writers.RST.tests
43 ]
45 ]
44 , testGroup "Readers"
46 , testGroup "Readers"
45 [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
47 [ testGroup "LaTeX" Tests.Readers.LaTeX.tests