git.iko.soy/typeable/pandoc
on master help sign in
hlint FB2 writer
81d2841Alexander Krotov
src/Text/Pandoc/Writers/FB2.hs+50−50
@@ -38,8 +38,8 @@ FictionBook is an XML-based e-book format. For more information see:
38module Text.Pandoc.Writers.FB2 (writeFB2) where
38module Text.Pandoc.Writers.FB2 (writeFB2) where
39
39
40import Control.Monad.Except (catchError)
40import Control.Monad.Except (catchError)
41−import Control.Monad.State.Strict (StateT, evalStateT, get, lift, modify)
41+import Control.Monad.State.Strict (StateT, evalStateT, get, lift, modify, liftM)
42−import Control.Monad.State.Strict (liftM)
42+import Control.Monad (zipWithM)
43import Data.ByteString.Base64 (encode)
43import Data.ByteString.Base64 (encode)
44import qualified Data.ByteString.Char8 as B8
44import qualified Data.ByteString.Char8 as B8
45import Data.Char (isAscii, isControl, isSpace, toLower)
45import Data.Char (isAscii, isControl, isSpace, toLower)
@@ -100,10 +100,10 @@ pandocToFB2 opts (Pandoc meta blocks) = do
100 secs <- renderSections 1 blocks
100 secs <- renderSections 1 blocks
101 let body = el "body" $ fp ++ secs
101 let body = el "body" $ fp ++ secs
102 notes <- renderFootnotes
102 notes <- renderFootnotes
103− (imgs,missing) <- liftM imagesToFetch get >>= \s -> lift (fetchImages s)
103+ (imgs,missing) <- fmap imagesToFetch get >>= \s -> lift (fetchImages s)
104 let body' = replaceImagesWithAlt missing body
104 let body' = replaceImagesWithAlt missing body
105 let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs)
105 let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs)
106− return $ pack $ xml_head ++ (showContent fb2_xml) ++ "\n"
106+ return $ pack $ xml_head ++ showContent fb2_xml ++ "\n"
107 where
107 where
108 xml_head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
108 xml_head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
109 fb2_attrs =
109 fb2_attrs =
@@ -115,7 +115,7 @@ pandocToFB2 opts (Pandoc meta blocks) = do
115frontpage :: PandocMonad m => Meta -> FBM m [Content]
115frontpage :: PandocMonad m => Meta -> FBM m [Content]
116frontpage meta' = do
116frontpage meta' = do
117 t <- cMapM toXml . docTitle $ meta'
117 t <- cMapM toXml . docTitle $ meta'
118− return $
118+ return
119 [ el "title" (el "p" t)
119 [ el "title" (el "p" t)
120 , el "annotation" (map (el "p" . cMap plain)
120 , el "annotation" (map (el "p" . cMap plain)
121 (docAuthors meta' ++ [docDate meta']))
121 (docAuthors meta' ++ [docDate meta']))
@@ -131,7 +131,7 @@ description meta' = do
131 Just (MetaString s) -> [el "lang" $ iso639 s]
131 Just (MetaString s) -> [el "lang" $ iso639 s]
132 _ -> []
132 _ -> []
133 where iso639 = takeWhile (/= '-') -- Convert BCP 47 to ISO 639
133 where iso639 = takeWhile (/= '-') -- Convert BCP 47 to ISO 639
134− return $ el "description" $
134+ return $ el "description"
135 [ el "title-info" (bt ++ as ++ dd ++ lang)
135 [ el "title-info" (bt ++ as ++ dd ++ lang)
136 , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version
136 , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version
137 ]
137 ]
@@ -149,16 +149,16 @@ authors meta' = cMap author (docAuthors meta')
149author :: [Inline] -> [Content]
149author :: [Inline] -> [Content]
150author ss =
150author ss =
151 let ws = words . cMap plain $ ss
151 let ws = words . cMap plain $ ss
152− email = (el "email") `fmap` (take 1 $ filter ('@' `elem`) ws)
152+ email = el "email" <$> take 1 (filter ('@' `elem`) ws)
153 ws' = filter ('@' `notElem`) ws
153 ws' = filter ('@' `notElem`) ws
154 names = case ws' of
154 names = case ws' of
155− (nickname:[]) -> [ el "nickname" nickname ]
155+ [nickname] -> [ el "nickname" nickname ]
156− (fname:lname:[]) -> [ el "first-name" fname
156+ [fname, lname] -> [ el "first-name" fname
157 , el "last-name" lname ]
157 , el "last-name" lname ]
158 (fname:rest) -> [ el "first-name" fname
158 (fname:rest) -> [ el "first-name" fname
159 , el "middle-name" (concat . init $ rest)
159 , el "middle-name" (concat . init $ rest)
160 , el "last-name" (last rest) ]
160 , el "last-name" (last rest) ]
161− ([]) -> []
161+ [] -> []
162 in list $ el "author" (names ++ email)
162 in list $ el "author" (names ++ email)
163
163
164docdate :: PandocMonad m => Meta -> FBM m [Content]
164docdate :: PandocMonad m => Meta -> FBM m [Content]
@@ -181,7 +181,7 @@ renderSection level (ttl, body) = do
181 title <- if null ttl
181 title <- if null ttl
182 then return []
182 then return []
183 else return . list . el "title" . formatTitle $ ttl
183 else return . list . el "title" . formatTitle $ ttl
184− content <- if (hasSubsections body)
184+ content <- if hasSubsections body
185 then renderSections (level + 1) body
185 then renderSections (level + 1) body
186 else cMapM blockToXml body
186 else cMapM blockToXml body
187 return $ el "section" (title ++ content)
187 return $ el "section" (title ++ content)
@@ -213,7 +213,7 @@ splitSections level blocks = reverse $ revSplit (reverse blocks)
213 let (lastsec, before) = break sameLevel rblocks
213 let (lastsec, before) = break sameLevel rblocks
214 (header, prevblocks) =
214 (header, prevblocks) =
215 case before of
215 case before of
216− ((Header n _ title):prevblocks') ->
216+ (Header n _ title:prevblocks') ->
217 if n == level
217 if n == level
218 then (title, prevblocks')
218 then (title, prevblocks')
219 else ([], before)
219 else ([], before)
@@ -232,7 +232,7 @@ renderFootnotes = do
232 el "body" ([uattr "name" "notes"], map renderFN (reverse fns))
232 el "body" ([uattr "name" "notes"], map renderFN (reverse fns))
233 where
233 where
234 renderFN (n, idstr, cs) =
234 renderFN (n, idstr, cs) =
235− let fn_texts = (el "title" (el "p" (show n))) : cs
235+ let fn_texts = el "title" (el "p" (show n)) : cs
236 in el "section" ([uattr "id" idstr], fn_texts)
236 in el "section" ([uattr "id" idstr], fn_texts)
237
237
238-- | Fetch images and encode them for the FictionBook XML.
238-- | Fetch images and encode them for the FictionBook XML.
@@ -240,7 +240,7 @@ renderFootnotes = do
240fetchImages :: PandocMonad m => [(String,String)] -> m ([Content],[String])
240fetchImages :: PandocMonad m => [(String,String)] -> m ([Content],[String])
241fetchImages links = do
241fetchImages links = do
242 imgs <- mapM (uncurry fetchImage) links
242 imgs <- mapM (uncurry fetchImage) links
243− return $ (rights imgs, lefts imgs)
243+ return (rights imgs, lefts imgs)
244
244
245-- | Fetch image data from disk or from network and make a <binary> XML section.
245-- | Fetch image data from disk or from network and make a <binary> XML section.
246-- Return either (Left hrefOfMissingImage) or (Right xmlContent).
246-- Return either (Left hrefOfMissingImage) or (Right xmlContent).
@@ -254,7 +254,7 @@ fetchImage href link = do
254 then return (Just (mime',base64))
254 then return (Just (mime',base64))
255 else return Nothing
255 else return Nothing
256 (True, Just _) -> return Nothing -- not base64-encoded
256 (True, Just _) -> return Nothing -- not base64-encoded
257− _ -> do
257+ _ ->
258 catchError (do (bs, mbmime) <- P.fetchItem link
258 catchError (do (bs, mbmime) <- P.fetchItem link
259 case mbmime of
259 case mbmime of
260 Nothing -> do
260 Nothing -> do
@@ -266,7 +266,7 @@ fetchImage href link = do
266 do report $ CouldNotFetchResource link (show e)
266 do report $ CouldNotFetchResource link (show e)
267 return Nothing)
267 return Nothing)
268 case mbimg of
268 case mbimg of
269− Just (imgtype, imgdata) -> do
269+ Just (imgtype, imgdata) ->
270 return . Right $ el "binary"
270 return . Right $ el "binary"
271 ( [uattr "id" href
271 ( [uattr "id" href
272 , uattr "content-type" imgtype]
272 , uattr "content-type" imgtype]
@@ -300,8 +300,8 @@ isMimeType :: String -> Bool
300isMimeType s =
300isMimeType s =
301 case split (=='/') s of
301 case split (=='/') s of
302 [mtype,msubtype] ->
302 [mtype,msubtype] ->
303− ((map toLower mtype) `elem` types
303+ (map toLower mtype `elem` types
304− || "x-" `isPrefixOf` (map toLower mtype))
304+ || "x-" `isPrefixOf` map toLower mtype)
305 && all valid mtype
305 && all valid mtype
306 && all valid msubtype
306 && all valid msubtype
307 _ -> False
307 _ -> False
@@ -311,10 +311,10 @@ isMimeType s =
311 c `notElem` "()<>@,;:\\\"/[]?="
311 c `notElem` "()<>@,;:\\\"/[]?="
312
312
313footnoteID :: Int -> String
313footnoteID :: Int -> String
314−footnoteID i = "n" ++ (show i)
314+footnoteID i = "n" ++ show i
315
315
316linkID :: Int -> String
316linkID :: Int -> String
317−linkID i = "l" ++ (show i)
317+linkID i = "l" ++ show i
318
318
319-- | Convert a block-level Pandoc's element to FictionBook XML representation.
319-- | Convert a block-level Pandoc's element to FictionBook XML representation.
320blockToXml :: PandocMonad m => Block -> FBM m [Content]
320blockToXml :: PandocMonad m => Block -> FBM m [Content]
@@ -323,14 +323,14 @@ blockToXml (Para [Math DisplayMath formula]) = insertMath NormalImage formula
323-- title beginning with fig: indicates that the image is a figure
323-- title beginning with fig: indicates that the image is a figure
324blockToXml (Para [Image atr alt (src,'f':'i':'g':':':tit)]) =
324blockToXml (Para [Image atr alt (src,'f':'i':'g':':':tit)]) =
325 insertImage NormalImage (Image atr alt (src,tit))
325 insertImage NormalImage (Image atr alt (src,tit))
326−blockToXml (Para ss) = liftM (list . el "p") $ cMapM toXml ss
326+blockToXml (Para ss) = (list . el "p") <$> cMapM toXml ss
327blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
327blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
328 map (el "p" . el "code") . lines $ s
328 map (el "p" . el "code") . lines $ s
329blockToXml b@(RawBlock _ _) = do
329blockToXml b@(RawBlock _ _) = do
330 report $ BlockNotRendered b
330 report $ BlockNotRendered b
331 return []
331 return []
332blockToXml (Div _ bs) = cMapM blockToXml bs
332blockToXml (Div _ bs) = cMapM blockToXml bs
333−blockToXml (BlockQuote bs) = liftM (list . el "cite") $ cMapM blockToXml bs
333+blockToXml (BlockQuote bs) = (list . el "cite") <$> cMapM blockToXml bs
334blockToXml (LineBlock lns) = blockToXml $ linesToPara lns
334blockToXml (LineBlock lns) = blockToXml $ linesToPara lns
335blockToXml (OrderedList a bss) = do
335blockToXml (OrderedList a bss) = do
336 state <- get
336 state <- get
@@ -341,19 +341,19 @@ blockToXml (OrderedList a bss) = do
341 itemtext <- cMapM blockToXml . paraToPlain $ bs
341 itemtext <- cMapM blockToXml . paraToPlain $ bs
342 modify (\s -> s { parentListMarker = pmrk }) -- old parent marker
342 modify (\s -> s { parentListMarker = pmrk }) -- old parent marker
343 return . el "p" $ [ txt mrk, txt " " ] ++ itemtext
343 return . el "p" $ [ txt mrk, txt " " ] ++ itemtext
344− mapM (uncurry mkitem) (zip markers bss)
344+ zipWithM mkitem markers bss
345blockToXml (BulletList bss) = do
345blockToXml (BulletList bss) = do
346 state <- get
346 state <- get
347 let level = parentBulletLevel state
347 let level = parentBulletLevel state
348 let pmrk = parentListMarker state
348 let pmrk = parentListMarker state
349 let prefix = replicate (length pmrk) ' '
349 let prefix = replicate (length pmrk) ' '
350 let bullets = ["\x2022", "\x25e6", "*", "\x2043", "\x2023"]
350 let bullets = ["\x2022", "\x25e6", "*", "\x2043", "\x2023"]
351− let mrk = prefix ++ bullets !! (level `mod` (length bullets))
351+ let mrk = prefix ++ bullets !! (level `mod` length bullets)
352 let mkitem bs = do
352 let mkitem bs = do
353− modify (\s -> s { parentBulletLevel = (level+1) })
353+ modify (\s -> s { parentBulletLevel = level+1 })
354 itemtext <- cMapM blockToXml . paraToPlain $ bs
354 itemtext <- cMapM blockToXml . paraToPlain $ bs
355 modify (\s -> s { parentBulletLevel = level }) -- restore bullet level
355 modify (\s -> s { parentBulletLevel = level }) -- restore bullet level
356− return $ el "p" $ [ txt (mrk ++ " ") ] ++ itemtext
356+ return $ el "p" $ txt (mrk ++ " ") : itemtext
357 mapM mkitem bss
357 mapM mkitem bss
358blockToXml (DefinitionList defs) =
358blockToXml (DefinitionList defs) =
359 cMapM mkdef defs
359 cMapM mkdef defs
@@ -370,7 +370,7 @@ blockToXml (DefinitionList defs) =
370 needsBreak (Para _) = False
370 needsBreak (Para _) = False
371 needsBreak (Plain ins) = LineBreak `notElem` ins
371 needsBreak (Plain ins) = LineBreak `notElem` ins
372 needsBreak _ = True
372 needsBreak _ = True
373−blockToXml h@(Header _ _ _) = do
373+blockToXml h@Header{} = do
374 -- should not occur after hierarchicalize, except inside lists/blockquotes
374 -- should not occur after hierarchicalize, except inside lists/blockquotes
375 report $ BlockNotRendered h
375 report $ BlockNotRendered h
376 return []
376 return []
@@ -381,12 +381,12 @@ blockToXml HorizontalRule = return
381blockToXml (Table caption aligns _ headers rows) = do
381blockToXml (Table caption aligns _ headers rows) = do
382 hd <- mkrow "th" headers aligns
382 hd <- mkrow "th" headers aligns
383 bd <- mapM (\r -> mkrow "td" r aligns) rows
383 bd <- mapM (\r -> mkrow "td" r aligns) rows
384− c <- return . el "emphasis" =<< cMapM toXml caption
384+ c <- el "emphasis" <$> cMapM toXml caption
385 return [el "table" (hd : bd), el "p" c]
385 return [el "table" (hd : bd), el "p" c]
386 where
386 where
387 mkrow :: PandocMonad m => String -> [TableCell] -> [Alignment] -> FBM m Content
387 mkrow :: PandocMonad m => String -> [TableCell] -> [Alignment] -> FBM m Content
388 mkrow tag cells aligns' =
388 mkrow tag cells aligns' =
389− (el "tr") `liftM` (mapM (mkcell tag) (zip cells aligns'))
389+ el "tr" <$> mapM (mkcell tag) (zip cells aligns')
390 --
390 --
391 mkcell :: PandocMonad m => String -> (TableCell, Alignment) -> FBM m Content
391 mkcell :: PandocMonad m => String -> (TableCell, Alignment) -> FBM m Content
392 mkcell tag (cell, align) = do
392 mkcell tag (cell, align) = do
@@ -405,7 +405,7 @@ blockToXml Null = return []
405paraToPlain :: [Block] -> [Block]
405paraToPlain :: [Block] -> [Block]
406paraToPlain [] = []
406paraToPlain [] = []
407paraToPlain (Para inlines : rest) =
407paraToPlain (Para inlines : rest) =
408− let p = (Plain (inlines ++ [LineBreak]))
408+ let p = Plain (inlines ++ [LineBreak])
409 in p : paraToPlain rest
409 in p : paraToPlain rest
410paraToPlain (p:rest) = p : paraToPlain rest
410paraToPlain (p:rest) = p : paraToPlain rest
411
411
@@ -418,8 +418,8 @@ indent = indentBlock
418 spacer :: String
418 spacer :: String
419 spacer = replicate 4 ' '
419 spacer = replicate 4 ' '
420 --
420 --
421− indentBlock (Plain ins) = Plain ((Str spacer):ins)
421+ indentBlock (Plain ins) = Plain (Str spacer:ins)
422− indentBlock (Para ins) = Para ((Str spacer):ins)
422+ indentBlock (Para ins) = Para (Str spacer:ins)
423 indentBlock (CodeBlock a s) =
423 indentBlock (CodeBlock a s) =
424 let s' = unlines . map (spacer++) . lines $ s
424 let s' = unlines . map (spacer++) . lines $ s
425 in CodeBlock a s'
425 in CodeBlock a s'
@@ -429,7 +429,7 @@ indent = indentBlock
429 -- indent every (explicit) line
429 -- indent every (explicit) line
430 indentLines :: [Inline] -> [Inline]
430 indentLines :: [Inline] -> [Inline]
431 indentLines ins = let lns = split isLineBreak ins :: [[Inline]]
431 indentLines ins = let lns = split isLineBreak ins :: [[Inline]]
432− in intercalate [LineBreak] $ map ((Str spacer):) lns
432+ in intercalate [LineBreak] $ map (Str spacer:) lns
433
433
434-- | Convert a Pandoc's Inline element to FictionBook XML representation.
434-- | Convert a Pandoc's Inline element to FictionBook XML representation.
435toXml :: PandocMonad m => Inline -> FBM m [Content]
435toXml :: PandocMonad m => Inline -> FBM m [Content]
@@ -473,7 +473,7 @@ toXml (Link _ text (url,ttl)) = do
473 ( [ attr ("l","href") ('#':ln_id)
473 ( [ attr ("l","href") ('#':ln_id)
474 , uattr "type" "note" ]
474 , uattr "type" "note" ]
475 , ln_ref) ]
475 , ln_ref) ]
476−toXml img@(Image _ _ _) = insertImage InlineImage img
476+toXml img@Image{} = insertImage InlineImage img
477toXml (Note bs) = do
477toXml (Note bs) = do
478 fns <- footnotes `liftM` get
478 fns <- footnotes `liftM` get
479 let n = 1 + length fns
479 let n = 1 + length fns
@@ -487,7 +487,7 @@ toXml (Note bs) = do
487
487
488insertMath :: PandocMonad m => ImageMode -> String -> FBM m [Content]
488insertMath :: PandocMonad m => ImageMode -> String -> FBM m [Content]
489insertMath immode formula = do
489insertMath immode formula = do
490− htmlMath <- return . writerHTMLMathMethod . writerOptions =<< get
490+ htmlMath <- fmap (writerHTMLMathMethod . writerOptions) get
491 case htmlMath of
491 case htmlMath of
492 WebTeX url -> do
492 WebTeX url -> do
493 let alt = [Code nullAttr formula]
493 let alt = [Code nullAttr formula]
@@ -531,17 +531,17 @@ replaceImagesWithAlt missingHrefs body =
531 Nothing -> c' -- end of document
531 Nothing -> c' -- end of document
532 --
532 --
533 isImage :: Content -> Bool
533 isImage :: Content -> Bool
534− isImage (Elem e) = (elName e) == (uname "image")
534+ isImage (Elem e) = elName e == uname "image"
535 isImage _ = False
535 isImage _ = False
536 --
536 --
537− isMissing (Elem img@(Element _ _ _ _)) =
537+ isMissing (Elem img@Element{}) =
538 let imgAttrs = elAttribs img
538 let imgAttrs = elAttribs img
539 badAttrs = map (attr ("l","href")) missingHrefs
539 badAttrs = map (attr ("l","href")) missingHrefs
540 in any (`elem` imgAttrs) badAttrs
540 in any (`elem` imgAttrs) badAttrs
541 isMissing _ = False
541 isMissing _ = False
542 --
542 --
543 replaceNode :: Content -> Content
543 replaceNode :: Content -> Content
544− replaceNode n@(Elem img@(Element _ _ _ _)) =
544+ replaceNode n@(Elem img@Element{}) =
545 let attrs = elAttribs img
545 let attrs = elAttribs img
546 alt = getAttrVal attrs (uname "alt")
546 alt = getAttrVal attrs (uname "alt")
547 imtype = getAttrVal attrs (qname "l" "type")
547 imtype = getAttrVal attrs (qname "l" "type")
@@ -572,15 +572,15 @@ list = (:[])
572-- | Convert an 'Inline' to plaintext.
572-- | Convert an 'Inline' to plaintext.
573plain :: Inline -> String
573plain :: Inline -> String
574plain (Str s) = s
574plain (Str s) = s
575−plain (Emph ss) = concat (map plain ss)
575+plain (Emph ss) = concatMap plain ss
576−plain (Span _ ss) = concat (map plain ss)
576+plain (Span _ ss) = concatMap plain ss
577−plain (Strong ss) = concat (map plain ss)
577+plain (Strong ss) = concatMap plain ss
578−plain (Strikeout ss) = concat (map plain ss)
578+plain (Strikeout ss) = concatMap plain ss
579−plain (Superscript ss) = concat (map plain ss)
579+plain (Superscript ss) = concatMap plain ss
580−plain (Subscript ss) = concat (map plain ss)
580+plain (Subscript ss) = concatMap plain ss
581−plain (SmallCaps ss) = concat (map plain ss)
581+plain (SmallCaps ss) = concatMap plain ss
582−plain (Quoted _ ss) = concat (map plain ss)
582+plain (Quoted _ ss) = concatMap plain ss
583−plain (Cite _ ss) = concat (map plain ss) -- FIXME
583+plain (Cite _ ss) = concatMap plain ss -- FIXME
584plain (Code _ s) = s
584plain (Code _ s) = s
585plain Space = " "
585plain Space = " "
586plain SoftBreak = " "
586plain SoftBreak = " "
@@ -588,7 +588,7 @@ plain LineBreak = "\n"
588plain (Math _ s) = s
588plain (Math _ s) = s
589plain (RawInline _ _) = ""
589plain (RawInline _ _) = ""
590plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"])
590plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"])
591−plain (Image _ alt _) = concat (map plain alt)
591+plain (Image _ alt _) = concatMap plain alt
592plain (Note _) = "" -- FIXME
592plain (Note _) = "" -- FIXME
593
593
594-- | Create an XML element.
594-- | Create an XML element.
@@ -610,11 +610,11 @@ txt s = Text $ CData CDataText s Nothing
610
610
611-- | Create an XML attribute with an unqualified name.
611-- | Create an XML attribute with an unqualified name.
612uattr :: String -> String -> Text.XML.Light.Attr
612uattr :: String -> String -> Text.XML.Light.Attr
613−uattr name val = Attr (uname name) val
613+uattr name = Attr (uname name)
614
614
615-- | Create an XML attribute with a qualified name from given namespace.
615-- | Create an XML attribute with a qualified name from given namespace.
616attr :: (String, String) -> String -> Text.XML.Light.Attr
616attr :: (String, String) -> String -> Text.XML.Light.Attr
617−attr (ns, name) val = Attr (qname ns name) val
617+attr (ns, name) = Attr (qname ns name)
618
618
619-- | Unqualified name
619-- | Unqualified name
620uname :: String -> QName
620uname :: String -> QName