git.iko.soy/typeable/pandoc
on master help sign in
Implement runTest functions.

These work with a State monad and a Reader monad to produce deterministic results. It can probably be simplified somewhat.

commit67282fed744bd00da035267ccde77365145b376f authorJesse Rosenthal <jrosenthal@jhu.edu> dateWed 16 Nov 2016, 20:49 (10 years ago) parent31bfa17
7 files changed+177−85
pandoc.cabal+1−1 src/Text/Pandoc/Free.hs+159−58 src/Text/Pandoc/UUID.hs+1−1 src/Text/Pandoc/Writers/Docx.hs+8−11 src/Text/Pandoc/Writers/EPUB.hs+3−5 src/Text/Pandoc/Writers/ICML.hs+3−5 src/Text/Pandoc/Writers/ODT.hs+2−4
pandoc.cabal+1−1
@@ -291,7 +291,7 @@ Library
291291 old-time,
292292 deepseq >= 1.3 && < 1.5,
293293 JuicyPixels >= 3.1.6.1 && < 3.3,
294− filemanip >= 0.3 && < 0.4,
294+ Glob >= 0.7 && < 0.8,
295295 cmark >= 0.5 && < 0.6,
296296 doctemplates >= 0.1 && < 0.2,
297297 free >= 4
src/Text/Pandoc/Free.hs+159−58
@@ -33,6 +33,7 @@ Pure implementations of the IO monads used in Pandoc's readers and writers.
3333module Text.Pandoc.Free ( PandocActionF(..)
3434 , PandocAction
3535 , runIO
36+ , runTest
3637 , liftF
3738 --
3839 , lookupEnv
@@ -41,7 +42,7 @@ module Text.Pandoc.Free ( PandocActionF(..)
4142 , getDefaultReferenceDocx
4243 , getDefaultReferenceODT
4344 , newStdGen
44− , newUnique
45+ , newUniqueHash
4546 , newUUID
4647 , readFileStrict
4748 , readFileLazy
@@ -51,18 +52,15 @@ module Text.Pandoc.Free ( PandocActionF(..)
5152 , fetchItem'
5253 , warn
5354 , fail
54− , newIORef
55− , modifyIORef
56− , readIORef
57− , namesMatching
55+ , glob
5856 ) where
5957
6058import Prelude hiding (readFile, fail)
6159import qualified Control.Monad as M (fail)
62−import System.Random (StdGen)
60+import System.Random (StdGen, next)
6361import qualified System.Random as IO (newStdGen)
64−import Codec.Archive.Zip (Archive)
65−import Data.Unique (Unique)
62+import Codec.Archive.Zip (Archive, fromArchive)
63+import Data.Unique (Unique, hashUnique, newUnique)
6664import qualified Data.Unique as IO (newUnique)
6765import qualified Text.Pandoc.Shared as IO ( fetchItem
6866 , fetchItem'
@@ -70,32 +68,35 @@ import qualified Text.Pandoc.Shared as IO ( fetchItem
7068 , getDefaultReferenceODT
7169 , warn
7270 , readDataFile)
73−import Text.Pandoc.MediaBag (MediaBag)
74−import Data.Time.Clock.POSIX (POSIXTime)
71+import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
72+import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds)
7573import qualified Data.Time.Clock.POSIX as IO (getPOSIXTime)
7674import Text.Pandoc.Compat.Time (UTCTime)
7775import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
78−import Text.Pandoc.MIME (MimeType)
76+import Text.Pandoc.MIME (MimeType, getMimeType)
7977import qualified Data.ByteString as B
8078import qualified Data.ByteString.Lazy as BL
8179import Control.Monad.Free
8280import qualified Control.Exception as E
8381import qualified System.Environment as IO (lookupEnv)
84−import Data.IORef (IORef)
85−import qualified Data.IORef as IO (newIORef, modifyIORef, readIORef)
86−import Text.Pandoc.UUID (UUID)
82+import Text.Pandoc.UUID
8783import qualified Text.Pandoc.UUID as IO (getRandomUUID)
88−import qualified Text.Pandoc.UTF8 as UTF8 (readFile)
89−import qualified System.FilePath.Glob as IO (namesMatching)
90−
91−data PandocActionF ref nxt =
84+import qualified Text.Pandoc.UTF8 as UTF8 (readFile, toString)
85+import System.FilePath.Glob (match, compile)
86+import System.FilePath ((</>))
87+import qualified System.FilePath.Glob as IO (glob)
88+import Control.Monad.State hiding (fail)
89+import Control.Monad.Reader hiding (fail)
90+import Data.Word (Word8)
91+
92+data PandocActionF nxt =
9293 LookupEnv String (Maybe String -> nxt)
9394 | GetCurrentTime (UTCTime -> nxt)
9495 | GetPOSIXTime (POSIXTime -> nxt)
9596 | GetDefaultReferenceDocx (Maybe FilePath) (Archive -> nxt)
9697 | GetDefaultReferenceODT (Maybe FilePath) (Archive -> nxt)
9798 | NewStdGen (StdGen -> nxt)
98− | NewUnique (Unique -> nxt)
99+ | NewUniqueHash (Int -> nxt)
99100 | NewUUID (UUID -> nxt)
100101 | ReadFileStrict FilePath (B.ByteString -> nxt)
101102 | ReadFileLazy FilePath (BL.ByteString -> nxt)
@@ -105,83 +106,71 @@ data PandocActionF ref nxt =
105106 (Either E.SomeException (B.ByteString, Maybe MimeType) -> nxt)
106107 | FetchItem' MediaBag (Maybe String) (String)
107108 (Either E.SomeException (B.ByteString, Maybe MimeType) -> nxt)
108− | NewIORef ref (IORef ref -> nxt)
109− | ModifyIORef (IORef ref) (ref -> ref) nxt
110− | ReadIORef (IORef ref) (ref -> nxt)
111− | NamesMatching String ([FilePath] -> nxt)
109+ | Glob String ([FilePath] -> nxt)
112110 | Warn String nxt
113111 | Fail String
114112 deriving Functor
115113
116−type PandocAction a = Free (PandocActionF a)
114+type PandocAction = Free PandocActionF
117115
118−lookupEnv :: String -> PandocAction a (Maybe String)
116+lookupEnv :: String -> PandocAction (Maybe String)
119117lookupEnv s = liftF $ LookupEnv s id
120118
121−getCurrentTime :: PandocAction a UTCTime
119+getCurrentTime :: PandocAction UTCTime
122120getCurrentTime = liftF $ GetCurrentTime id
123121
124−getPOSIXTime :: PandocAction a POSIXTime
122+getPOSIXTime :: PandocAction POSIXTime
125123getPOSIXTime = liftF $ GetPOSIXTime id
126124
127−getDefaultReferenceDocx :: Maybe FilePath -> PandocAction a Archive
125+getDefaultReferenceDocx :: Maybe FilePath -> PandocAction Archive
128126getDefaultReferenceDocx fp = liftF $ GetDefaultReferenceDocx fp id
129127
130−getDefaultReferenceODT :: Maybe FilePath -> PandocAction a Archive
128+getDefaultReferenceODT :: Maybe FilePath -> PandocAction Archive
131129getDefaultReferenceODT fp = liftF $ GetDefaultReferenceODT fp id
132130
133−newStdGen :: PandocAction a StdGen
131+newStdGen :: PandocAction StdGen
134132newStdGen = liftF $ NewStdGen id
135133
136−newUnique :: PandocAction a Unique
137−newUnique = liftF $ NewUnique id
134+newUniqueHash :: PandocAction Int
135+newUniqueHash = liftF $ NewUniqueHash id
138136
139−newUUID :: PandocAction a UUID
137+newUUID :: PandocAction UUID
140138newUUID = liftF $ NewUUID id
141139
142−readFileStrict :: FilePath -> PandocAction a B.ByteString
140+readFileStrict :: FilePath -> PandocAction B.ByteString
143141readFileStrict fp = liftF $ ReadFileStrict fp id
144142
145−readFileLazy :: FilePath -> PandocAction a BL.ByteString
143+readFileLazy :: FilePath -> PandocAction BL.ByteString
146144readFileLazy fp = liftF $ ReadFileLazy fp id
147145
148−readFileUTF8 :: FilePath -> PandocAction a String
146+readFileUTF8 :: FilePath -> PandocAction String
149147readFileUTF8 fp = liftF $ ReadFileUTF8 fp id
150148
151−readDataFile :: Maybe FilePath -> FilePath -> PandocAction a B.ByteString
149+readDataFile :: Maybe FilePath -> FilePath -> PandocAction B.ByteString
152150readDataFile mfp fp = liftF $ ReadDataFile mfp fp id
153151
154152fetchItem :: Maybe String ->
155153 String ->
156− PandocAction a (Either E.SomeException (B.ByteString, Maybe MimeType))
154+ PandocAction (Either E.SomeException (B.ByteString, Maybe MimeType))
157155fetchItem ms s = liftF $ FetchItem ms s id
158156
159157
160158fetchItem' :: MediaBag ->
161159 Maybe String ->
162160 String ->
163− PandocAction a (Either E.SomeException (B.ByteString, Maybe MimeType))
161+ PandocAction (Either E.SomeException (B.ByteString, Maybe MimeType))
164162fetchItem' mb ms s = liftF $ FetchItem' mb ms s id
165163
166−warn :: String -> PandocAction a ()
164+warn :: String -> PandocAction ()
167165warn s = liftF $ Warn s ()
168166
169−fail :: String -> PandocAction a b
167+fail :: String -> PandocAction b
170168fail s = liftF $ Fail s
171169
172−newIORef :: a -> PandocAction a (IORef a)
173−newIORef v = liftF $ NewIORef v id
174−
175−modifyIORef :: (IORef a) -> (a -> a) -> PandocAction a ()
176−modifyIORef ref f = liftF $ ModifyIORef ref f ()
177−
178−readIORef :: (IORef a) -> PandocAction a a
179−readIORef ref = liftF $ ReadIORef ref id
180−
181−namesMatching :: String -> PandocAction a [FilePath]
182−namesMatching s = liftF $ NamesMatching s id
170+glob :: String -> PandocAction [FilePath]
171+glob s = liftF $ Glob s id
183172
184−runIO :: PandocAction ref nxt -> IO nxt
173+runIO :: PandocAction nxt -> IO nxt
185174runIO (Free (LookupEnv s f)) = IO.lookupEnv s >>= runIO . f
186175runIO (Free (GetCurrentTime f)) = IO.getCurrentTime >>= runIO . f
187176runIO (Free (GetPOSIXTime f)) = IO.getPOSIXTime >>= runIO . f
@@ -190,7 +179,7 @@ runIO (Free (GetDefaultReferenceDocx mfp f)) =
190179runIO (Free (GetDefaultReferenceODT mfp f)) =
191180 IO.getDefaultReferenceODT mfp >>= runIO . f
192181runIO (Free (NewStdGen f)) = IO.newStdGen >>= runIO . f
193−runIO (Free (NewUnique f)) = IO.newUnique >>= runIO . f
182+runIO (Free (NewUniqueHash f)) = hashUnique <$> IO.newUnique >>= runIO . f
194183runIO (Free (NewUUID f)) = IO.getRandomUUID >>= runIO . f
195184runIO (Free (ReadFileStrict fp f)) = B.readFile fp >>= runIO . f
196185runIO (Free (ReadFileLazy fp f)) = BL.readFile fp >>= runIO . f
@@ -202,8 +191,120 @@ runIO (Free (FetchItem sourceUrl nm f)) =
202191runIO (Free (FetchItem' media sourceUrl nm f)) =
203192 IO.fetchItem' media sourceUrl nm >>= runIO . f
204193runIO (Free (Warn s nxt)) = IO.warn s >> runIO nxt
205−runIO (Free (NewIORef v f)) = IO.newIORef v >>= runIO . f
206−runIO (Free (ModifyIORef ref f nxt)) = IO.modifyIORef ref f >> runIO nxt
207−runIO (Free (ReadIORef ref f)) = IO.readIORef ref >>= runIO . f
208−runIO (Free (NamesMatching s f)) = IO.namesMatching s >>= runIO . f
194+runIO (Free (Glob s f)) = IO.glob s >>= runIO . f
209195runIO (Pure r) = return r
196+
197+data TestState = TestState { stStdGen :: StdGen
198+ , stWord8Store :: [Word8] -- should be
199+ -- inifinite,
200+ -- i.e. [1..]
201+ , stWarnings :: [String]
202+ , stUniqStore :: [Int] -- should be
203+ -- inifinite and
204+ -- contain every
205+ -- element at most
206+ -- once, e.g. [1..]
207+ }
208+
209+data TestEnv = TestEnv { envEnv :: [(String, String)]
210+ , envTime :: UTCTime
211+ , envReferenceDocx :: Archive
212+ , envReferenceODT :: Archive
213+ , envFiles :: [(FilePath, B.ByteString)]
214+ , envUserDataDir :: [(FilePath, B.ByteString)]
215+ , envCabalDataDir :: [(FilePath, B.ByteString)]
216+ , envFontFiles :: [FilePath]
217+ }
218+
219+data TestException = TestException
220+ deriving (Show)
221+
222+instance E.Exception TestException
223+
224+type Testing = ReaderT TestEnv (State TestState)
225+
226+runTest :: PandocAction nxt -> Testing nxt
227+runTest (Free (LookupEnv s f)) = do
228+ env <- asks envEnv
229+ return (lookup s env) >>= runTest . f
230+runTest (Free (GetCurrentTime f)) =
231+ asks envTime >>= runTest . f
232+runTest (Free (GetPOSIXTime f)) =
233+ (utcTimeToPOSIXSeconds <$> asks envTime) >>= runTest . f
234+runTest (Free (GetDefaultReferenceDocx _ f)) =
235+ asks envReferenceDocx >>= runTest . f
236+runTest (Free (GetDefaultReferenceODT _ f)) =
237+ asks envReferenceODT >>= runTest . f
238+runTest (Free (NewStdGen f)) = do
239+ g <- gets stStdGen
240+ let (_, nxtGen) = next g
241+ modify $ \st -> st { stStdGen = nxtGen }
242+ return g >>= runTest . f
243+runTest (Free (NewUniqueHash f)) = do
244+ uniqs <- gets stUniqStore
245+ case uniqs of
246+ u : us -> do
247+ modify $ \st -> st { stUniqStore = us }
248+ return u >>= runTest . f
249+ _ -> M.fail "uniq store ran out of elements"
250+runTest (Free (NewUUID f)) = do
251+ word8s <- gets stWord8Store
252+ case word8s of
253+ -- note we use f' because f is a param of the function
254+ a:b:c:d:e:f':g:h:i:j:k:l:m:n:o:p:remaining -> do
255+ modify $ \st -> st { stWord8Store = remaining }
256+ return (UUID a b c d e f' g h i j k l m n o p) >>= runTest . f
257+ _ -> M.fail "word8 supply was not infinite"
258+runTest (Free (ReadFileStrict fp f)) = do
259+ fps <- asks envFiles
260+ case lookup fp fps of
261+ Just bs -> return bs >>= runTest . f
262+ Nothing -> error "openFile: does not exist"
263+runTest (Free (ReadFileLazy fp f)) = do
264+ fps <- asks envFiles
265+ case lookup fp fps of
266+ Just bs -> return (BL.fromStrict bs) >>= runTest . f
267+ Nothing -> error "openFile: does not exist"
268+runTest (Free (ReadFileUTF8 fp f)) = do
269+ fps <- asks envFiles
270+ case lookup fp fps of
271+ Just bs -> return (UTF8.toString bs) >>= runTest . f
272+ Nothing -> error "openFile: does not exist"
273+-- A few different cases of readDataFile to reimplement, for when
274+-- there is no filepath and it falls through to readDefaultDataFile
275+runTest (Free (ReadDataFile Nothing "reference.docx" f)) = do
276+ (B.concat . BL.toChunks . fromArchive) <$>
277+ (runTest $ getDefaultReferenceDocx Nothing) >>=
278+ runTest . f
279+runTest (Free (ReadDataFile Nothing "reference.odt" f)) = do
280+ (B.concat . BL.toChunks . fromArchive) <$>
281+ (runTest $ getDefaultReferenceODT Nothing) >>=
282+ runTest . f
283+runTest (Free (ReadDataFile Nothing fname f)) = do
284+ let fname' = if fname == "MANUAL.txt" then fname else "data" </> fname
285+ runTest (readFileStrict fname') >>= runTest . f
286+runTest (Free (ReadDataFile (Just userDir) fname f)) = do
287+ userDirFiles <- asks envUserDataDir
288+ case lookup (userDir </> fname) userDirFiles of
289+ Just bs -> return bs >>= runTest . f
290+ Nothing -> runTest (readDataFile Nothing fname) >>= runTest . f
291+runTest (Free (Fail s)) = M.fail s
292+runTest (Free (FetchItem _ fp f)) = do
293+ fps <- asks envFiles
294+ case lookup fp fps of
295+ Just bs -> return (Right (bs, getMimeType fp)) >>= runTest . f
296+ Nothing -> return (Left $ E.toException TestException) >>= runTest . f
297+runTest (Free (FetchItem' media sourceUrl nm f)) = do
298+ case lookupMedia nm media of
299+ Nothing -> runTest (fetchItem sourceUrl nm) >>= runTest . f
300+ Just (mime, bs) -> return (Right (B.concat $ BL.toChunks bs, Just mime)) >>= runTest . f
301+runTest (Free (Warn s nxt)) = do
302+ modify $ \st -> st { stWarnings = s : stWarnings st }
303+ runTest nxt
304+runTest (Free (Glob s f)) = do
305+ fontFiles <- asks envFontFiles
306+ return (filter (match (compile s)) fontFiles) >>= runTest . f
307+runTest (Pure r) = return r
308+
309+
310+
src/Text/Pandoc/UUID.hs+1−1
@@ -29,7 +29,7 @@ UUID generation using Version 4 (random method) described
2929in RFC4122. See http://tools.ietf.org/html/rfc4122
3030-}
3131
32−module Text.Pandoc.UUID ( UUID, getRandomUUID ) where
32+module Text.Pandoc.UUID ( UUID(..), getRandomUUID ) where
3333
3434import Text.Printf ( printf )
3535import System.Random ( randomIO )
src/Text/Pandoc/Writers/Docx.hs+8−11
@@ -56,7 +56,6 @@ import Text.Pandoc.Readers.Docx.Util (elemName)
5656import Control.Monad.Reader
5757import Control.Monad.State
5858import Text.Highlighting.Kate
59−import Data.Unique (hashUnique)
6059import System.Random (randomR)
6160import Text.Printf (printf)
6261import qualified Control.Exception as E
@@ -69,8 +68,6 @@ import Data.Char (ord, isSpace, toLower)
6968import Text.Pandoc.Free (PandocAction, runIO)
7069import qualified Text.Pandoc.Free as P
7170
72−type DocxAction = PandocAction ()
73−
7471data ListMarker = NoMarker
7572 | BulletMarker
7673 | NumberMarker ListNumberStyle ListNumberDelim Int
@@ -149,7 +146,7 @@ defaultWriterState = WriterState{
149146 , stDynamicTextProps = []
150147 }
151148
152−type WS = ReaderT WriterEnv (StateT WriterState (DocxAction))
149+type WS = ReaderT WriterEnv (StateT WriterState (PandocAction))
153150
154151mknode :: Node t => String -> [(String,String)] -> t -> Element
155152mknode s attrs =
@@ -227,7 +224,7 @@ writeDocx opts doc = runIO $ writeDocxPure opts doc
227224-- | Produce an Docx file from a Pandoc document.
228225writeDocxPure :: WriterOptions -- ^ Writer options
229226 -> Pandoc -- ^ Document to convert
230− -> DocxAction BL.ByteString
227+ -> PandocAction BL.ByteString
231228writeDocxPure opts doc@(Pandoc meta _) = do
232229 let datadir = writerUserDataDir opts
233230 let doc' = walk fixDisplayMath $ doc
@@ -614,7 +611,7 @@ styleToOpenXml sm style =
614611 $ backgroundColor style )
615612 ]
616613
617−copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> DocxAction Entry
614+copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> PandocAction Entry
618615copyChildren refArchive distArchive path timestamp elNames = do
619616 ref <- parseXml refArchive distArchive path
620617 dist <- parseXml distArchive distArchive path
@@ -633,7 +630,7 @@ copyChildren refArchive distArchive path timestamp elNames = do
633630baseListId :: Int
634631baseListId = 1000
635632
636−mkNumbering :: [ListMarker] -> DocxAction [Element]
633+mkNumbering :: [ListMarker] -> PandocAction [Element]
637634mkNumbering lists = do
638635 elts <- mapM mkAbstractNum (ordNub lists)
639636 return $ elts ++ zipWith mkNum lists [baseListId..(baseListId + length lists - 1)]
@@ -649,7 +646,7 @@ mkNum marker numid =
649646 map (\lvl -> mknode "w:lvlOverride" [("w:ilvl",show (lvl :: Int))]
650647 $ mknode "w:startOverride" [("w:val",show start)] ()) [0..6]
651648
652−mkAbstractNum :: ListMarker -> DocxAction Element
649+mkAbstractNum :: ListMarker -> PandocAction Element
653650mkAbstractNum marker = do
654651 gen <- P.newStdGen
655652 let (nsid, _) = randomR (0x10000000 :: Integer, 0xFFFFFFFF :: Integer) gen
@@ -794,10 +791,10 @@ rStyleM styleName = do
794791 let sty' = getStyleId styleName $ sCharStyleMap styleMaps
795792 return $ mknode "w:rStyle" [("w:val",sty')] ()
796793
797−getUniqueId :: DocxAction String
794+getUniqueId :: PandocAction String
798795-- the + 20 is to ensure that there are no clashes with the rIds
799796-- already in word/document.xml.rel
800−getUniqueId = (show . (+ 20) . hashUnique) <$> P.newUnique
797+getUniqueId = (show . (+ 20)) <$> P.newUniqueHash
801798
802799-- | Key for specifying user-defined docx styles.
803800dynamicStyleKey :: String
@@ -1274,7 +1271,7 @@ defaultFootnotes = [ mknode "w:footnote"
12741271 [ mknode "w:r" [] $
12751272 [ mknode "w:continuationSeparator" [] ()]]]]
12761273
1277−parseXml :: Archive -> Archive -> String -> DocxAction Element
1274+parseXml :: Archive -> Archive -> String -> PandocAction Element
12781275parseXml refArchive distArchive relpath =
12791276 case findEntryByPath relpath refArchive `mplus`
12801277 findEntryByPath relpath distArchive of
src/Text/Pandoc/Writers/EPUB.hs+3−5
@@ -66,8 +66,6 @@ import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags)
6666import Text.Pandoc.Free (PandocAction, runIO)
6767import qualified Text.Pandoc.Free as P
6868
69−type EPUBAction = PandocAction [(FilePath, (FilePath, Maybe Entry))]
70−
7169-- A Chapter includes a list of blocks and maybe a section
7270-- number offset. Note, some chapters are unnumbered. The section
7371-- number is different from the index number, which will be used
@@ -77,7 +75,7 @@ data Chapter = Chapter (Maybe [Int]) [Block]
7775data EPUBState = EPUBState { stMediaPaths :: [(FilePath, (FilePath, Maybe Entry))]
7876 }
7977
80−type E = StateT EPUBState EPUBAction
78+type E = StateT EPUBState PandocAction
8179
8280data EPUBMetadata = EPUBMetadata{
8381 epubIdentifier :: [Identifier]
@@ -343,7 +341,7 @@ writeEPUB opts doc = runIO $ writeEPUBPure opts doc
343341
344342writeEPUBPure :: WriterOptions -- ^ Writer options
345343 -> Pandoc -- ^ Document to convert
346− -> EPUBAction B.ByteString
344+ -> PandocAction B.ByteString
347345writeEPUBPure opts doc =
348346 let initState = EPUBState { stMediaPaths = []
349347 }
@@ -399,7 +397,7 @@ pandocToEPUB opts doc@(Pandoc meta _) = do
399397 picEntries <- (catMaybes . map (snd . snd)) <$> (gets stMediaPaths)
400398 -- handle fonts
401399 let matchingGlob f = do
402− xs <- lift $ P.namesMatching f
400+ xs <- lift $ P.glob f
403401 when (null xs) $
404402 lift $ P.warn $ f ++ " did not match any font files."
405403 return xs
src/Text/Pandoc/Writers/ICML.hs+3−5
@@ -28,11 +28,9 @@ import Data.Text as Text (breakOnAll, pack)
2828import Control.Monad.State
2929import Network.URI (isURI)
3030import qualified Data.Set as Set
31−import Text.Pandoc.Free (runIO)
31+import Text.Pandoc.Free (runIO, PandocAction)
3232import qualified Text.Pandoc.Free as P
3333
34−type ICMLAction = P.PandocAction ()
35−
3634type Style = [String]
3735type Hyperlink = [(Int, String)]
3836
@@ -44,7 +42,7 @@ data WriterState = WriterState{
4442 , maxListDepth :: Int
4543 }
4644
47−type WS a = StateT WriterState ICMLAction a
45+type WS a = StateT WriterState PandocAction a
4846
4947defaultWriterState :: WriterState
5048defaultWriterState = WriterState{
@@ -130,7 +128,7 @@ writeICML :: WriterOptions -> Pandoc -> IO String
130128writeICML opts doc = runIO $ writeICMLPure opts doc
131129
132130-- | Convert Pandoc document to string in ICML format.
133−writeICMLPure :: WriterOptions -> Pandoc -> ICMLAction String
131+writeICMLPure :: WriterOptions -> Pandoc -> PandocAction String
134132writeICMLPure opts (Pandoc meta blocks) = do
135133 let colwidth = if writerWrapText opts == WrapAuto
136134 then Just $ writerColumns opts
src/Text/Pandoc/Writers/ODT.hs+2−4
@@ -53,12 +53,10 @@ import System.FilePath ( takeExtension, takeDirectory, (<.>))
5353import Text.Pandoc.Free ( PandocAction, runIO )
5454import qualified Text.Pandoc.Free as P
5555
56−type ODTAction = PandocAction [Entry]
57−
5856data ODTState = ODTState { stEntries :: [Entry]
5957 }
6058
61−type O = StateT ODTState ODTAction
59+type O = StateT ODTState PandocAction
6260
6361-- | Produce an ODT file from a Pandoc document.
6462writeODT :: WriterOptions -- ^ Writer options
@@ -68,7 +66,7 @@ writeODT opts doc = runIO $ writeODTPure opts doc
6866
6967writeODTPure :: WriterOptions
7068 -> Pandoc
71− -> ODTAction B.ByteString
69+ -> PandocAction B.ByteString
7270writeODTPure opts doc =
7371 let initState = ODTState{ stEntries = []
7472 }