git.iko.soy/typeable/pandoc
on master help sign in
Muse writer: add support for --reference-location=

Address #107

commit0c84630549c4b452d2eb5a3d82df5fc62ca593e6 authorAlexander Krotov <ilabdsf@gmail.com> dateMon 5 Nov 2018, 07:27 (8 years ago) parenta4968d7
2 files changed+129−9
src/Text/Pandoc/Writers/Muse.hs+44−6 test/Tests/Writers/Muse.hs+85−3
src/Text/Pandoc/Writers/Muse.hs+44−6
@@ -80,12 +80,14 @@ data WriterEnv =
8080
8181data WriterState =
8282 WriterState { stNotes :: Notes
83+ , stNoteNum :: Int
8384 , stIds :: Set.Set String
8485 , stUseTags :: Bool -- ^ Use tags for emphasis, for example because previous character is a letter
8586 }
8687
8788instance Default WriterState
8889 where def = WriterState { stNotes = []
90+ , stNoteNum = 1
8991 , stIds = Set.empty
9092 , stUseTags = False
9193 }
@@ -127,7 +129,7 @@ pandocToMuse (Pandoc meta blocks) = do
127129 (fmap render' . inlineListToMuse)
128130 meta
129131 body <- blockListToMuse blocks
130− notes <- fmap (reverse . stNotes) get >>= notesToMuse
132+ notes <- currentNotesToMuse
131133 let main = render colwidth $ body $+$ notes
132134 let context = defField "body" main metadata
133135 case writerTemplate opts of
@@ -141,7 +143,7 @@ catWithBlankLines :: PandocMonad m
141143 -> Int -- ^ Number of blank lines
142144 -> Muse m Doc
143145catWithBlankLines (b : bs) n = do
144− b' <- blockToMuse b
146+ b' <- blockToMuseWithNotes b
145147 bs' <- flatBlockListToMuse bs
146148 return $ b' <> blanklines n <> bs'
147149catWithBlankLines _ _ = error "Expected at least one block"
@@ -290,26 +292,61 @@ blockToMuse (Table caption aligns widths headers rows) =
290292blockToMuse (Div _ bs) = flatBlockListToMuse bs
291293blockToMuse Null = return empty
292294
295+-- | Return Muse representation of notes collected so far.
296+currentNotesToMuse :: PandocMonad m
297+ => Muse m Doc
298+currentNotesToMuse = do
299+ notes <- reverse <$> gets stNotes
300+ modify $ \st -> st { stNotes = mempty }
301+ notesToMuse notes
302+
293303-- | Return Muse representation of notes.
294304notesToMuse :: PandocMonad m
295305 => Notes
296306 -> Muse m Doc
297−notesToMuse notes = vsep <$> zipWithM noteToMuse [1 ..] notes
307+notesToMuse notes = do
308+ n <- gets stNoteNum
309+ modify $ \st -> st { stNoteNum = stNoteNum st + length notes }
310+ vsep <$> zipWithM noteToMuse [n ..] notes
298311
299312-- | Return Muse representation of a note.
300313noteToMuse :: PandocMonad m
301314 => Int
302315 -> [Block]
303316 -> Muse m Doc
304−noteToMuse num note =
305− hang (length marker) (text marker) <$>
317+noteToMuse num note = do
318+ res <- hang (length marker) (text marker) <$>
306319 local (\env -> env { envInsideBlock = True
307320 , envInlineStart = True
308321 , envAfterSpace = True
309322 }) (blockListToMuse note)
323+ return $ res <> blankline
310324 where
311325 marker = "[" ++ show num ++ "] "
312326
327+-- | Return Muse representation of block and accumulated notes.
328+blockToMuseWithNotes :: PandocMonad m
329+ => Block
330+ -> Muse m Doc
331+blockToMuseWithNotes blk = do
332+ topLevel <- asks envTopLevel
333+ opts <- asks envOptions
334+ let hdrToMuse hdr@(Header{}) = do
335+ b <- blockToMuse hdr
336+ if topLevel && writerReferenceLocation opts == EndOfSection
337+ then do
338+ notes <- currentNotesToMuse
339+ return $ notes $+$ b
340+ else
341+ return b
342+ hdrToMuse b = blockToMuse b
343+ b <- hdrToMuse blk
344+ if topLevel && writerReferenceLocation opts == EndOfBlock
345+ then do
346+ notes <- currentNotesToMuse
347+ return $ b $+$ notes <> blankline
348+ else return b
349+
313350-- | Escape special characters for Muse.
314351escapeString :: String -> String
315352escapeString s =
@@ -659,7 +696,8 @@ inlineToMuse (Note contents) = do
659696 modify $ \st -> st { stNotes = contents:notes
660697 , stUseTags = False
661698 }
662− let ref = show $ length notes + 1
699+ n <- gets stNoteNum
700+ let ref = show $ n + length notes
663701 return $ "[" <> text ref <> "]"
664702inlineToMuse (Span (anchor,names,_) inlines) = do
665703 contents <- inlineListToMuse inlines
test/Tests/Writers/Muse.hs+85−3
@@ -9,10 +9,13 @@ import Text.Pandoc
99import Text.Pandoc.Arbitrary ()
1010import Text.Pandoc.Builder
1111
12+defopts :: WriterOptions
13+defopts = def{ writerWrapText = WrapPreserve,
14+ writerExtensions = extensionsFromList [Ext_amuse,
15+ Ext_auto_identifiers] }
16+
1217muse :: (ToPandoc a) => a -> String
13−muse = museWithOpts def{ writerWrapText = WrapPreserve,
14− writerExtensions = extensionsFromList [Ext_amuse,
15− Ext_auto_identifiers] }
18+muse = museWithOpts defopts
1619
1720museWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
1821museWithOpts opts = unpack . purely (writeMuse opts) . toPandoc
@@ -22,6 +25,84 @@ infix 4 =:
2225 => String -> (a, String) -> TestTree
2326(=:) = test muse
2427
28+noteLocationTestDoc :: Blocks
29+noteLocationTestDoc =
30+ header 1 (text "First Header") <>
31+ para (text "This is a footnote." <>
32+ note (para (text "First note."))) <>
33+ blockQuote (para (text "A note inside a block quote." <>
34+ note (para (text "The second note."))) <>
35+ para (text "A second paragraph.")) <>
36+ header 1 (text "Second Header") <>
37+ para (text "Some more text.")
38+
39+noteLocationTests :: TestTree
40+noteLocationTests = testGroup "note location"
41+ [ test (museWithOpts defopts {writerReferenceLocation=EndOfDocument})
42+ "footnotes at the end of document" $
43+ noteLocationTestDoc =?>
44+ (unlines [ "* First Header"
45+ , ""
46+ , "This is a footnote.[1]"
47+ , ""
48+ , "<quote>"
49+ , "A note inside a block quote.[2]"
50+ , ""
51+ , "A second paragraph."
52+ , "</quote>"
53+ , ""
54+ , "* Second Header"
55+ , ""
56+ , "Some more text."
57+ , ""
58+ , "[1] First note."
59+ , ""
60+ , "[2] The second note."
61+ ])
62+ , test (museWithOpts defopts {writerReferenceLocation=EndOfBlock})
63+ "footnotes at the end of block" $
64+ noteLocationTestDoc =?>
65+ (unlines [ "* First Header"
66+ , ""
67+ , "This is a footnote.[1]"
68+ , ""
69+ , "[1] First note."
70+ , ""
71+ , "<quote>"
72+ , "A note inside a block quote.[2]"
73+ , ""
74+ , "[2] The second note."
75+ , ""
76+ , "A second paragraph."
77+ , "</quote>"
78+ , ""
79+ , "* Second Header"
80+ , ""
81+ , "Some more text."
82+ ])
83+ , test (museWithOpts defopts {writerReferenceLocation=EndOfSection})
84+ "footnotes at the end of section" $
85+ noteLocationTestDoc =?>
86+ (unlines [ "* First Header"
87+ , ""
88+ , "This is a footnote.[1]"
89+ , ""
90+ , "<quote>"
91+ , "A note inside a block quote.[2]"
92+ , ""
93+ , "A second paragraph."
94+ , "</quote>"
95+ , ""
96+ , "[1] First note."
97+ , ""
98+ , "[2] The second note."
99+ , ""
100+ , "* Second Header"
101+ , ""
102+ , "Some more text."
103+ ])
104+ ]
105+
25106tests :: [TestTree]
26107tests = [ testGroup "block elements"
27108 [ "plain" =: plain (text "Foo bar.") =?> "Foo bar."
@@ -501,6 +582,7 @@ tests = [ testGroup "block elements"
501582 , ""
502583 , "[1] Foo"
503584 ]
585+ , noteLocationTests
504586 , "span with class" =: spanWith ("",["foobar"],[]) (text "Some text")
505587 =?> "<class name=\"foobar\">Some text</class>"
506588 , "span without class" =: spanWith ("",[],[]) (text "Some text")