@@ -49,25 +49,40 @@ import Text.Pandoc.Shared ( escapeURI, removeFormatting, camelCaseToHyphenated
4949import Text.Pandoc.Writers.Shared ( defField, metaToJSON )
5050import Text.Pandoc.Templates ( renderTemplate' )
5151import Data.List ( intersect, intercalate, isPrefixOf )
52+import Data.Default (Default(..))
5253import Network.URI ( isURI )
5354import Control.Monad ( zipWithM )
54−import Control.Monad.State ( modify, State, get, gets, evalState )
55+import Control.Monad.State ( modify, State, get, evalState )
56+import Control.Monad.Reader ( ReaderT, runReaderT, ask, local )
5557import Control.Applicative ( (<$>) )
5658
5759data WriterState = WriterState {
5860 stNotes :: Bool -- True if there are notes
59− , stIndent :: String -- Indent after the marker at the beginning of list items
61+ }
62+
63+data WriterEnvironment = WriterEnvironment {
64+ stIndent :: String -- Indent after the marker at the beginning of list items
6065 , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
6166 }
6267
68+instance Default WriterState where
69+ def = WriterState { stNotes = False }
70+
71+instance Default WriterEnvironment where
72+ def = WriterEnvironment { stIndent = "", stUseTags = False }
73+
74+type DokuWiki = ReaderT WriterEnvironment (State WriterState)
75+
6376-- | Convert Pandoc to DokuWiki.
6477writeDokuWiki :: WriterOptions -> Pandoc -> String
6578writeDokuWiki opts document =
66− evalState (pandocToDokuWiki opts $ normalize document)
67− (WriterState { stNotes = False, stIndent = "", stUseTags = False })
79+ runDokuWiki (pandocToDokuWiki opts $ normalize document)
80+
81+runDokuWiki :: DokuWiki a -> a
82+runDokuWiki = flip evalState def . flip runReaderT def
6883
6984-- | Return DokuWiki representation of document.
70−pandocToDokuWiki :: WriterOptions -> Pandoc -> State WriterState String
85+pandocToDokuWiki :: WriterOptions -> Pandoc -> DokuWiki String
7186pandocToDokuWiki opts (Pandoc meta blocks) = do
7287 metadata <- metaToJSON opts
7388 (fmap trimr . blockListToDokuWiki opts)
@@ -96,7 +111,7 @@ escapeString = substitute "__" "%%__%%" .
96111-- | Convert Pandoc block element to DokuWiki.
97112blockToDokuWiki :: WriterOptions -- ^ Options
98113 -> Block -- ^ Block element
99− -> State WriterState String
114+ -> DokuWiki String
100115
101116blockToDokuWiki _ Null = return ""
102117
@@ -119,8 +134,8 @@ blockToDokuWiki opts (Para [Image txt (src,'f':'i':'g':':':tit)]) = do
119134 return $ "{{:" ++ src ++ opt ++ "}}\n"
120135
121136blockToDokuWiki opts (Para inlines) = do
122− indent <- gets stIndent
123− useTags <- gets stUseTags
137+ indent <- stIndent <$> ask
138+ useTags <- stUseTags <$> ask
124139 contents <- inlineListToDokuWiki opts inlines
125140 return $ if useTags
126141 then "<HTML><p></HTML>" ++ contents ++ "<HTML></p></HTML>"
@@ -180,54 +195,48 @@ blockToDokuWiki opts (Table capt aligns _ headers rows') = do
180195 unlines body'
181196
182197blockToDokuWiki opts x@(BulletList items) = do
183− oldUseTags <- stUseTags <$> get
184− indent <- stIndent <$> get
198+ oldUseTags <- stUseTags <$> ask
199+ indent <- stIndent <$> ask
185200 let useTags = oldUseTags || not (isSimpleList x)
186201 if useTags
187202 then do
188− modify $ \s -> s { stUseTags = True }
189− contents <- mapM (listItemToDokuWiki opts) items
190− modify $ \s -> s { stUseTags = oldUseTags }
203+ contents <- local (\s -> s { stUseTags = True })
204+ (mapM (listItemToDokuWiki opts) items)
191205 return $ "<HTML><ul></HTML>\n" ++ vcat contents ++ "<HTML></ul></HTML>\n"
192206 else do
193− modify $ \s -> s { stIndent = stIndent s ++ " " }
194− contents <- mapM (listItemToDokuWiki opts) items
195− modify $ \s -> s { stIndent = indent }
207+ contents <- local (\s -> s { stIndent = stIndent s ++ " " })
208+ (mapM (listItemToDokuWiki opts) items)
196209 return $ vcat contents ++ if null indent then "\n" else ""
197210
198211blockToDokuWiki opts x@(OrderedList attribs items) = do
199− oldUseTags <- stUseTags <$> get
200− indent <- stIndent <$> get
212+ oldUseTags <- stUseTags <$> ask
213+ indent <- stIndent <$> ask
201214 let useTags = oldUseTags || not (isSimpleList x)
202215 if useTags
203216 then do
204− modify $ \s -> s { stUseTags = True }
205− contents <- mapM (orderedListItemToDokuWiki opts) items
206− modify $ \s -> s { stUseTags = oldUseTags }
217+ contents <- local (\s -> s { stUseTags = True })
218+ (mapM (orderedListItemToDokuWiki opts) items)
207219 return $ "<HTML><ol" ++ listAttribsToString attribs ++ "></HTML>\n" ++ vcat contents ++ "<HTML></ol></HTML>\n"
208220 else do
209− modify $ \s -> s { stIndent = stIndent s ++ " " }
210− contents <- mapM (orderedListItemToDokuWiki opts) items
211− modify $ \s -> s { stIndent = indent }
221+ contents <- local (\s -> s { stIndent = stIndent s ++ " " })
222+ (mapM (orderedListItemToDokuWiki opts) items)
212223 return $ vcat contents ++ if null indent then "\n" else ""
213224
214225-- TODO Need to decide how to make definition lists work on dokuwiki - I don't think there
215226-- is a specific representation of them.
216227-- TODO This creates double '; ; ' if there is a bullet or ordered list inside a definition list
217228blockToDokuWiki opts x@(DefinitionList items) = do
218− oldUseTags <- stUseTags <$> get
219− indent <- stIndent <$> get
229+ oldUseTags <- stUseTags <$> ask
230+ indent <- stIndent <$> ask
220231 let useTags = oldUseTags || not (isSimpleList x)
221232 if useTags
222233 then do
223− modify $ \s -> s { stUseTags = True }
224− contents <- mapM (definitionListItemToDokuWiki opts) items
225− modify $ \s -> s { stUseTags = oldUseTags }
234+ contents <- local (\s -> s { stUseTags = True })
235+ (mapM (definitionListItemToDokuWiki opts) items)
226236 return $ "<HTML><dl></HTML>\n" ++ vcat contents ++ "<HTML></dl></HTML>\n"
227237 else do
228− modify $ \s -> s { stIndent = stIndent s ++ " " }
229− contents <- mapM (definitionListItemToDokuWiki opts) items
230− modify $ \s -> s { stIndent = indent }
238+ contents <- local (\s -> s { stIndent = stIndent s ++ " " })
239+ (mapM (definitionListItemToDokuWiki opts) items)
231240 return $ vcat contents ++ if null indent then "\n" else ""
232241
233242-- Auxiliary functions for lists:
@@ -244,41 +253,41 @@ listAttribsToString (startnum, numstyle, _) =
244253 else "")
245254
246255-- | Convert bullet list item (list of blocks) to DokuWiki.
247−listItemToDokuWiki :: WriterOptions -> [Block] -> State WriterState String
256+listItemToDokuWiki :: WriterOptions -> [Block] -> DokuWiki String
248257listItemToDokuWiki opts items = do
249258 contents <- blockListToDokuWiki opts items
250− useTags <- stUseTags <$> get
259+ useTags <- stUseTags <$> ask
251260 if useTags
252261 then return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
253262 else do
254− indent <- stIndent <$> get
263+ indent <- stIndent <$> ask
255264 return $ indent ++ "* " ++ contents
256265
257266-- | Convert ordered list item (list of blocks) to DokuWiki.
258267-- | TODO Emiminate dreadful duplication of text from listItemToDokuWiki
259−orderedListItemToDokuWiki :: WriterOptions -> [Block] -> State WriterState String
268+orderedListItemToDokuWiki :: WriterOptions -> [Block] -> DokuWiki String
260269orderedListItemToDokuWiki opts items = do
261270 contents <- blockListToDokuWiki opts items
262− useTags <- stUseTags <$> get
271+ useTags <- stUseTags <$> ask
263272 if useTags
264273 then return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
265274 else do
266− indent <- stIndent <$> get
275+ indent <- stIndent <$> ask
267276 return $ indent ++ "- " ++ contents
268277
269278-- | Convert definition list item (label, list of blocks) to DokuWiki.
270279definitionListItemToDokuWiki :: WriterOptions
271280 -> ([Inline],[[Block]])
272− -> State WriterState String
281+ -> DokuWiki String
273282definitionListItemToDokuWiki opts (label, items) = do
274283 labelText <- inlineListToDokuWiki opts label
275284 contents <- mapM (blockListToDokuWiki opts) items
276− useTags <- stUseTags <$> get
285+ useTags <- stUseTags <$> ask
277286 if useTags
278287 then return $ "<HTML><dt></HTML>" ++ labelText ++ "<HTML></dt></HTML>\n" ++
279288 (intercalate "\n" $ map (\d -> "<HTML><dd></HTML>" ++ d ++ "<HTML></dd></HTML>") contents)
280289 else do
281− indent <- stIndent <$> get
290+ indent <- stIndent <$> ask
282291 return $ indent ++ "* **" ++ labelText ++ "** " ++ concat contents
283292
284293-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
@@ -332,7 +341,7 @@ tableHeaderToDokuWiki :: WriterOptions
332341 -> [String]
333342 -> Int
334343 -> [[Block]]
335− -> State WriterState String
344+ -> DokuWiki String
336345tableHeaderToDokuWiki opts alignStrings rownum cols' = do
337346 let celltype = if rownum == 0 then "" else ""
338347 cols'' <- zipWithM
@@ -344,7 +353,7 @@ tableRowToDokuWiki :: WriterOptions
344353 -> [String]
345354 -> Int
346355 -> [[Block]]
347− -> State WriterState String
356+ -> DokuWiki String
348357tableRowToDokuWiki opts alignStrings rownum cols' = do
349358 let celltype = if rownum == 0 then "" else ""
350359 cols'' <- zipWithM
@@ -363,7 +372,7 @@ tableItemToDokuWiki :: WriterOptions
363372 -> String
364373 -> String
365374 -> [Block]
366− -> State WriterState String
375+ -> DokuWiki String
367376-- TODO Fix celltype and align' defined but not used
368377tableItemToDokuWiki opts _celltype _align' item = do
369378 let mkcell x = "" ++ x ++ ""
@@ -381,17 +390,17 @@ joinHeaders = intercalate " ^ "
381390-- | Convert list of Pandoc block elements to DokuWiki.
382391blockListToDokuWiki :: WriterOptions -- ^ Options
383392 -> [Block] -- ^ List of block elements
384− -> State WriterState String
393+ -> DokuWiki String
385394blockListToDokuWiki opts blocks =
386395 vcat <$> mapM (blockToDokuWiki opts) blocks
387396
388397-- | Convert list of Pandoc inline elements to DokuWiki.
389−inlineListToDokuWiki :: WriterOptions -> [Inline] -> State WriterState String
398+inlineListToDokuWiki :: WriterOptions -> [Inline] -> DokuWiki String
390399inlineListToDokuWiki opts lst =
391400 concat <$> (mapM (inlineToDokuWiki opts) lst)
392401
393402-- | Convert Pandoc inline element to DokuWiki.
394−inlineToDokuWiki :: WriterOptions -> Inline -> State WriterState String
403+inlineToDokuWiki :: WriterOptions -> Inline -> DokuWiki String
395404
396405inlineToDokuWiki opts (Span _attrs ils) =
397406 inlineListToDokuWiki opts ils