@@ -1,7 +1,11 @@
1{-# LANGUAGE NoImplicitPrelude #-}
1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE ViewPatterns #-}
5{-# LANGUAGE ViewPatterns #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6 Module : Text.Pandoc.Readers.Docx.Parse
10 Module : Text.Pandoc.Readers.Docx.Parse
7 Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
11 Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
@@ -31,6 +35,8 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
31 , VertAlign(..)
35 , VertAlign(..)
32 , ParIndentation(..)
36 , ParIndentation(..)
33 , ParagraphStyle(..)
37 , ParagraphStyle(..)
39+ , CharStyle(cStyleData)
35 , Cell(..)
41 , Cell(..)
36 , TrackedChange(..)
42 , TrackedChange(..)
@@ -38,8 +44,17 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
38 , ChangeInfo(..)
44 , ChangeInfo(..)
39 , FieldInfo(..)
45 , FieldInfo(..)
40 , Level(..)
46 , Level(..)
41 , archiveToDocx
52 , archiveToDocx
42 , archiveToDocxWithWarnings
53 , archiveToDocxWithWarnings
56+ , constructBogusParStyleData
57+ , leftBiasedMergeRunStyle
44import Prelude
59import Prelude
45import Codec.Archive.Zip
60import Codec.Archive.Zip
@@ -49,10 +64,13 @@ import Control.Monad.Reader
49import Control.Monad.State.Strict
64import Control.Monad.State.Strict
50import Data.Bits ((.|.))
65import Data.Bits ((.|.))
51import qualified Data.ByteString.Lazy as B
66import qualified Data.ByteString.Lazy as B
52−import Data.Char (chr, ord, readLitChar)
67+import Data.Char (chr, ord, readLitChar, toLower)
53import Data.List
68import Data.List
69+import Data.Function (on)
70+import Data.String (IsString(..))
54import qualified Data.Map as M
71import qualified Data.Map as M
55import Data.Maybe
72import Data.Maybe
56import System.FilePath
74import System.FilePath
57import Text.Pandoc.Readers.Docx.Util
75import Text.Pandoc.Readers.Docx.Util
58import Text.Pandoc.Readers.Docx.Fields
76import Text.Pandoc.Readers.Docx.Fields
@@ -121,9 +139,9 @@ unwrap :: NameSpaces -> Content -> [Content]
121unwrap ns (Elem element)
139unwrap ns (Elem element)
122 | isElem ns "w" "sdt" element
140 | isElem ns "w" "sdt" element
123 , Just sdtContent <- findChildByName ns "w" "sdtContent" element
141 , Just sdtContent <- findChildByName ns "w" "sdtContent" element
124− = concatMap ((unwrap ns) . Elem) (elChildren sdtContent)
142+ = concatMap (unwrap ns . Elem) (elChildren sdtContent)
125 | isElem ns "w" "smartTag" element
143 | isElem ns "w" "smartTag" element
126− = concatMap ((unwrap ns) . Elem) (elChildren element)
144+ = concatMap (unwrap ns . Elem) (elChildren element)
127unwrap _ content = [content]
145unwrap _ content = [content]
129unwrapChild :: NameSpaces -> Content -> Content
147unwrapChild :: NameSpaces -> Content -> Content
@@ -149,24 +167,20 @@ walkDocument ns element =
149 _ -> Nothing
167 _ -> Nothing
152−data Docx = Docx Document
170+newtype Docx = Docx Document
153 deriving Show
171 deriving Show
155data Document = Document NameSpaces Body
173data Document = Document NameSpaces Body
156 deriving Show
174 deriving Show
158−data Body = Body [BodyPart]
176+newtype Body = Body [BodyPart]
159 deriving Show
177 deriving Show
161type Media = [(FilePath, B.ByteString)]
179type Media = [(FilePath, B.ByteString)]
163−type CharStyle = (String, RunStyle)
181+type CharStyleMap = M.Map CharStyleId CharStyle
165−type ParStyle = (String, ParStyleData)
167−type CharStyleMap = M.Map String RunStyle
169−type ParStyleMap = M.Map String ParStyleData
183+type ParStyleMap = M.Map ParaStyleId ParStyle
171data Numbering = Numbering NameSpaces [Numb] [AbstractNumb]
185data Numbering = Numbering NameSpaces [Numb] [AbstractNumb]
172 deriving Show
186 deriving Show
@@ -213,12 +227,9 @@ data ChangeInfo = ChangeInfo ChangeId Author ChangeDate
213data TrackedChange = TrackedChange ChangeType ChangeInfo
227data TrackedChange = TrackedChange ChangeType ChangeInfo
214 deriving Show
228 deriving Show
216−data ParagraphStyle = ParagraphStyle { pStyle :: [String]
230+data ParagraphStyle = ParagraphStyle { pStyle :: [ParStyle]
217 , indentation :: Maybe ParIndentation
231 , indentation :: Maybe ParIndentation
218 , dropCap :: Bool
232 , dropCap :: Bool
219− , pHeading :: Maybe (String, Int)
220− , pNumInfo :: Maybe (String, String)
221− , pBlockQuote :: Maybe Bool
222 , pChange :: Maybe TrackedChange
233 , pChange :: Maybe TrackedChange
224 deriving Show
235 deriving Show
@@ -227,9 +238,6 @@ defaultParagraphStyle :: ParagraphStyle
227defaultParagraphStyle = ParagraphStyle { pStyle = []
238defaultParagraphStyle = ParagraphStyle { pStyle = []
228 , indentation = Nothing
239 , indentation = Nothing
229 , dropCap = False
240 , dropCap = False
230− , pHeading = Nothing
231− , pNumInfo = Nothing
232− , pBlockQuote = Nothing
233 , pChange = Nothing
241 , pChange = Nothing
@@ -242,18 +250,61 @@ data BodyPart = Paragraph ParagraphStyle [ParPart]
243type TblGrid = [Integer]
251type TblGrid = [Integer]
245−data TblLook = TblLook {firstRowFormatting::Bool}
253+newtype TblLook = TblLook {firstRowFormatting::Bool}
246 deriving Show
254 deriving Show
248defaultTblLook :: TblLook
256defaultTblLook :: TblLook
249defaultTblLook = TblLook{firstRowFormatting = False}
257defaultTblLook = TblLook{firstRowFormatting = False}
251−data Row = Row [Cell]
259+newtype Row = Row [Cell]
252 deriving Show
260 deriving Show
254−data Cell = Cell [BodyPart]
262+newtype Cell = Cell [BodyPart]
255 deriving Show
263 deriving Show
265+newtype CharStyleId = CharStyleId { fromCharStyleId :: String }
266+ deriving (Show, Eq, Ord, FromStyleId)
267+newtype ParaStyleId = ParaStyleId { fromParaStyleId :: String }
268+ deriving (Show, Eq, Ord, FromStyleId)
270+newtype CharStyleName = CharStyleName { fromCharStyleName :: CIString }
271+ deriving (Show, Eq, Ord, IsString, FromStyleName)
272+newtype ParaStyleName = ParaStyleName { fromParaStyleName :: CIString }
273+ deriving (Show, Eq, Ord, IsString, FromStyleName)
275+-- Case-insensitive comparisons
276+newtype CIString = CIString String deriving (Show, IsString, FromStyleName)
278+class FromStyleName a where
279+ fromStyleName :: a -> String
281+instance FromStyleName String where
284+class FromStyleId a where
285+ fromStyleId :: a -> String
287+instance FromStyleId String where
290+instance Eq CIString where
291+ (==) = (==) `on` map toLower . coerce
293+instance Ord CIString where
294+ compare = compare `on` map toLower . coerce
296+leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
297+leftBiasedMergeRunStyle a b = RunStyle
298+ { isBold = isBold a <|> isBold b
299+ , isItalic = isItalic a <|> isItalic b
300+ , isSmallCaps = isSmallCaps a <|> isSmallCaps b
301+ , isStrike = isStrike a <|> isStrike b
302+ , isRTL = isRTL a <|> isRTL b
303+ , rVertAlign = rVertAlign a <|> rVertAlign b
304+ , rUnderline = rUnderline a <|> rUnderline b
305+ , rParentStyle = rParentStyle a
257-- (width, height) in EMUs
308-- (width, height) in EMUs
258type Extent = Maybe (Double, Double)
309type Extent = Maybe (Double, Double)
@@ -285,21 +336,28 @@ data RunElem = TextRun String | LnBrk | Tab | SoftHyphen | NoBreakHyphen
285data VertAlign = BaseLn | SupScrpt | SubScrpt
336data VertAlign = BaseLn | SupScrpt | SubScrpt
286 deriving Show
337 deriving Show
339+data CharStyle = CharStyle { cStyleId :: CharStyleId
340+ , cStyleName :: CharStyleName
341+ , cStyleData :: RunStyle
288−data RunStyle = RunStyle { isBold :: Maybe Bool
344+data RunStyle = RunStyle { isBold :: Maybe Bool
289− , isItalic :: Maybe Bool
345+ , isItalic :: Maybe Bool
290− , isSmallCaps :: Maybe Bool
346+ , isSmallCaps :: Maybe Bool
291− , isStrike :: Maybe Bool
347+ , isStrike :: Maybe Bool
292− , isRTL :: Maybe Bool
348+ , isRTL :: Maybe Bool
293− , rVertAlign :: Maybe VertAlign
349+ , rVertAlign :: Maybe VertAlign
294− , rUnderline :: Maybe String
350+ , rUnderline :: Maybe String
295− , rStyle :: Maybe CharStyle
351+ , rParentStyle :: Maybe CharStyle
297 deriving Show
353 deriving Show
299−data ParStyleData = ParStyleData { headingLev :: Maybe (String, Int)
355+data ParStyle = ParStyle { headingLev :: Maybe (ParaStyleName, Int)
300− , isBlockQuote :: Maybe Bool
301− , numInfo :: Maybe (String, String)
356+ , numInfo :: Maybe (String, String)
302− , psStyle :: Maybe ParStyle}
357+ , psParentStyle :: Maybe ParStyle
358+ , pStyleName :: ParaStyleName
359+ , pStyleId :: ParaStyleId
303 deriving Show
361 deriving Show
305defaultRunStyle :: RunStyle
363defaultRunStyle :: RunStyle
@@ -310,7 +368,7 @@ defaultRunStyle = RunStyle { isBold = Nothing
310 , isRTL = Nothing
368 , isRTL = Nothing
311 , rVertAlign = Nothing
369 , rVertAlign = Nothing
312 , rUnderline = Nothing
370 , rUnderline = Nothing
313− , rStyle = Nothing
371+ , rParentStyle = Nothing
316type Target = String
374type Target = String
@@ -390,7 +448,10 @@ elemToBody ns element | isElem ns "w" "body" element =
390elemToBody _ _ = throwError WrongElem
448elemToBody _ _ = throwError WrongElem
392archiveToStyles :: Archive -> (CharStyleMap, ParStyleMap)
450archiveToStyles :: Archive -> (CharStyleMap, ParStyleMap)
393−archiveToStyles zf =
451+archiveToStyles = archiveToStyles' getStyleId getStyleId
452+archiveToStyles' :: (Ord k1, Ord k2, ElemToStyle a1, ElemToStyle a2) =>
453+ (a1 -> k1) -> (a2 -> k2) -> Archive -> (M.Map k1 a1, M.Map k2 a2)
454+archiveToStyles' conv1 conv2 zf =
394 let stylesElem = findEntryByPath "word/styles.xml" zf >>=
455 let stylesElem = findEntryByPath "word/styles.xml" zf >>=
395 (parseXMLDoc . UTF8.toStringLazy . fromEntry)
456 (parseXMLDoc . UTF8.toStringLazy . fromEntry)
@@ -399,19 +460,17 @@ archiveToStyles zf =
399 Just styElem ->
460 Just styElem ->
400 let namespaces = elemToNameSpaces styElem
461 let namespaces = elemToNameSpaces styElem
402− ( M.fromList $ buildBasedOnList namespaces styElem
463+ ( M.fromList $ map (\r -> (conv1 r, r)) $ buildBasedOnList namespaces styElem Nothing,
403− (Nothing :: Maybe CharStyle),
464+ M.fromList $ map (\p -> (conv2 p, p)) $ buildBasedOnList namespaces styElem Nothing)
404− M.fromList $ buildBasedOnList namespaces styElem
405− (Nothing :: Maybe ParStyle) )
407−isBasedOnStyle :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> Bool
466+isBasedOnStyle :: (ElemToStyle a, FromStyleId (StyleId a)) => NameSpaces -> Element -> Maybe a -> Bool
408isBasedOnStyle ns element parentStyle
467isBasedOnStyle ns element parentStyle
409 | isElem ns "w" "style" element
468 | isElem ns "w" "style" element
410 , Just styleType <- findAttrByName ns "w" "type" element
469 , Just styleType <- findAttrByName ns "w" "type" element
411 , styleType == cStyleType parentStyle
470 , styleType == cStyleType parentStyle
412 , Just basedOnVal <- findChildByName ns "w" "basedOn" element >>=
471 , Just basedOnVal <- findChildByName ns "w" "basedOn" element >>=
413 findAttrByName ns "w" "val"
472 findAttrByName ns "w" "val"
414− , Just ps <- parentStyle = basedOnVal == getStyleId ps
473+ , Just ps <- parentStyle = basedOnVal == fromStyleId (getStyleId ps)
415 | isElem ns "w" "style" element
474 | isElem ns "w" "style" element
416 , Just styleType <- findAttrByName ns "w" "type" element
475 , Just styleType <- findAttrByName ns "w" "type" element
417 , styleType == cStyleType parentStyle
476 , styleType == cStyleType parentStyle
@@ -419,30 +478,70 @@ isBasedOnStyle ns element parentStyle
419 , Nothing <- parentStyle = True
478 , Nothing <- parentStyle = True
420 | otherwise = False
479 | otherwise = False
422−class ElemToStyle a where
481+class HasStyleId a => ElemToStyle a where
423 cStyleType :: Maybe a -> String
482 cStyleType :: Maybe a -> String
424 elemToStyle :: NameSpaces -> Element -> Maybe a -> Maybe a
483 elemToStyle :: NameSpaces -> Element -> Maybe a -> Maybe a
485+class FromStyleId (StyleId a) => HasStyleId a where
425− getStyleId :: a -> String
487+ getStyleId :: a -> StyleId a
489+class FromStyleName (StyleName a) => HasStyleName a where
491+ getStyleName :: a -> StyleName a
493+class HasParentStyle a where
494+ getParentStyle :: a -> Maybe a
496+instance HasParentStyle CharStyle where
497+ getParentStyle = rParentStyle . cStyleData
499+instance HasParentStyle ParStyle where
500+ getParentStyle = psParentStyle
502+getStyleNames :: (Functor t, HasStyleName a) => t a -> t (StyleName a)
503+getStyleNames = fmap getStyleName
505+constructBogusParStyleData :: ParaStyleName -> ParStyle
506+constructBogusParStyleData stName = ParStyle
507+ { headingLev = Nothing
509+ , psParentStyle = Nothing
510+ , pStyleName = stName
511+ , pStyleId = ParaStyleId . filter (/=' ') . fromStyleName $ stName
427instance ElemToStyle CharStyle where
514instance ElemToStyle CharStyle where
428 cStyleType _ = "character"
515 cStyleType _ = "character"
429 elemToStyle ns element parentStyle
516 elemToStyle ns element parentStyle
430 | isElem ns "w" "style" element
517 | isElem ns "w" "style" element
431− , Just "character" <- findAttrByName ns "w" "type" element
518+ , Just "character" <- findAttrByName ns "w" "type" element =
432− , Just styleId <- findAttrByName ns "w" "styleId" element =
433− Just (styleId, elemToRunStyle ns element parentStyle)
519+ elemToCharStyle ns element parentStyle
434 | otherwise = Nothing
520 | otherwise = Nothing
522+instance HasStyleId CharStyle where
523+ type StyleId CharStyle = CharStyleId
435− getStyleId s = fst s
524+ getStyleId = cStyleId
526+instance HasStyleName CharStyle where
527+ type StyleName CharStyle = CharStyleName
528+ getStyleName = cStyleName
437instance ElemToStyle ParStyle where
530instance ElemToStyle ParStyle where
438 cStyleType _ = "paragraph"
531 cStyleType _ = "paragraph"
439 elemToStyle ns element parentStyle
532 elemToStyle ns element parentStyle
440 | isElem ns "w" "style" element
533 | isElem ns "w" "style" element
441 , Just "paragraph" <- findAttrByName ns "w" "type" element
534 , Just "paragraph" <- findAttrByName ns "w" "type" element
442− , Just styleId <- findAttrByName ns "w" "styleId" element =
443− Just (styleId, elemToParStyleData ns element parentStyle)
535+ = elemToParStyleData ns element parentStyle
444 | otherwise = Nothing
536 | otherwise = Nothing
538+instance HasStyleId ParStyle where
539+ type StyleId ParStyle = ParaStyleId
445− getStyleId s = fst s
540+ getStyleId = pStyleId
542+instance HasStyleName ParStyle where
543+ type StyleName ParStyle = ParaStyleName
544+ getStyleName = pStyleName
447getStyleChildren :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> [a]
546getStyleChildren :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> [a]
448getStyleChildren ns element parentStyle
547getStyleChildren ns element parentStyle
@@ -495,7 +594,7 @@ filePathToRelType "word/_rels/endnotes.xml.rels" _ = Just InEndnote
495-- -- to see if it's a documentPath, we have to check against the dynamic
594-- -- to see if it's a documentPath, we have to check against the dynamic
496-- -- docPath specified in "_rels/.rels"
595-- -- docPath specified in "_rels/.rels"
497filePathToRelType path docXmlPath =
596filePathToRelType path docXmlPath =
498− if path == "word/_rels/" ++ (takeFileName docXmlPath) ++ ".rels"
597+ if path == "word/_rels/" ++ takeFileName docXmlPath ++ ".rels"
499 then Just InDocument
598 then Just InDocument
500 else Nothing
599 else Nothing
@@ -537,7 +636,7 @@ lookupLevel numId ilvl (Numbering _ numbs absNumbs) = do
537 case lvlOverride of
636 case lvlOverride of
538 Just (LevelOverride _ _ (Just lvl')) -> Just lvl'
637 Just (LevelOverride _ _ (Just lvl')) -> Just lvl'
539 Just (LevelOverride _ (Just strt) _) ->
638 Just (LevelOverride _ (Just strt) _) ->
540− lookup ilvl $ map (\(Level i fmt s _) -> (i, (Level i fmt s (Just strt)))) lvls
639+ lookup ilvl $ map (\(Level i fmt s _) -> (i, Level i fmt s (Just strt))) lvls
542 lookup ilvl $ map (\l@(Level i _ _ _) -> (i, l)) lvls
641 lookup ilvl $ map (\l@(Level i _ _ _) -> (i, l)) lvls
@@ -693,6 +792,12 @@ testBitMask bitMaskS n =
693stringToInteger :: String -> Maybe Integer
792stringToInteger :: String -> Maybe Integer
694stringToInteger s = listToMaybe $ map fst (reads s :: [(Integer, String)])
793stringToInteger s = listToMaybe $ map fst (reads s :: [(Integer, String)])
795+pHeading :: ParagraphStyle -> Maybe (ParaStyleName, Int)
796+pHeading = getParStyleField headingLev . pStyle
798+pNumInfo :: ParagraphStyle -> Maybe (String, String)
799+pNumInfo = getParStyleField numInfo . pStyle
696elemToBodyPart :: NameSpaces -> Element -> D BodyPart
801elemToBodyPart :: NameSpaces -> Element -> D BodyPart
697elemToBodyPart ns element
802elemToBodyPart ns element
698 | isElem ns "w" "p" element
803 | isElem ns "w" "p" element
@@ -703,23 +808,19 @@ elemToBodyPart ns element
703elemToBodyPart ns element
808elemToBodyPart ns element
704 | isElem ns "w" "p" element
809 | isElem ns "w" "p" element
705 , Just (numId, lvl) <- getNumInfo ns element = do
810 , Just (numId, lvl) <- getNumInfo ns element = do
706− sty <- asks envParStyles
707− let parstyle = elemToParagraphStyle ns element sty
811+ parstyle <- elemToParagraphStyle ns element <$> asks envParStyles
708 parparts <- mapD (elemToParPart ns) (elChildren element)
812 parparts <- mapD (elemToParPart ns) (elChildren element)
709− num <- asks envNumbering
710− let levelInfo = lookupLevel numId lvl num
813+ levelInfo <- lookupLevel numId lvl <$> asks envNumbering
711 return $ ListItem parstyle numId lvl levelInfo parparts
814 return $ ListItem parstyle numId lvl levelInfo parparts
712elemToBodyPart ns element
815elemToBodyPart ns element
713 | isElem ns "w" "p" element = do
816 | isElem ns "w" "p" element = do
714− sty <- asks envParStyles
715− let parstyle = elemToParagraphStyle ns element sty
817+ parstyle <- elemToParagraphStyle ns element <$> asks envParStyles
716 parparts <- mapD (elemToParPart ns) (elChildren element)
818 parparts <- mapD (elemToParPart ns) (elChildren element)
717 -- Word uses list enumeration for numbered headings, so we only
819 -- Word uses list enumeration for numbered headings, so we only
718 -- want to infer a list from the styles if it is NOT a heading.
820 -- want to infer a list from the styles if it is NOT a heading.
719 case pHeading parstyle of
821 case pHeading parstyle of
720 Nothing | Just (numId, lvl) <- pNumInfo parstyle -> do
822 Nothing | Just (numId, lvl) <- pNumInfo parstyle -> do
721− num <- asks envNumbering
722− let levelInfo = lookupLevel numId lvl num
823+ levelInfo <- lookupLevel numId lvl <$> asks envNumbering
723 return $ ListItem parstyle numId lvl levelInfo parparts
824 return $ ListItem parstyle numId lvl levelInfo parparts
724 _ -> return $ Paragraph parstyle parparts
825 _ -> return $ Paragraph parstyle parparts
725elemToBodyPart ns element
826elemToBodyPart ns element
@@ -727,7 +828,7 @@ elemToBodyPart ns element
727 let caption' = findChildByName ns "w" "tblPr" element
828 let caption' = findChildByName ns "w" "tblPr" element
728 >>= findChildByName ns "w" "tblCaption"
829 >>= findChildByName ns "w" "tblCaption"
729 >>= findAttrByName ns "w" "val"
830 >>= findAttrByName ns "w" "val"
730− caption = (fromMaybe "" caption')
831+ caption = fromMaybe "" caption'
731 grid' = case findChildByName ns "w" "tblGrid" element of
832 grid' = case findChildByName ns "w" "tblGrid" element of
732 Just g -> elemToTblGrid ns g
833 Just g -> elemToTblGrid ns g
733 Nothing -> return []
834 Nothing -> return []
@@ -1007,20 +1108,18 @@ elemToRun ns element
1007 return $ Run runStyle runElems
1108 return $ Run runStyle runElems
1008elemToRun _ _ = throwError WrongElem
1109elemToRun _ _ = throwError WrongElem
1010−getParentStyleValue :: (ParStyleData -> Maybe a) -> ParStyleData -> Maybe a
1111+getParentStyleValue :: (ParStyle -> Maybe a) -> ParStyle -> Maybe a
1011getParentStyleValue field style
1112getParentStyleValue field style
1012 | Just value <- field style = Just value
1113 | Just value <- field style = Just value
1013− | Just parentStyle <- psStyle style
1114+ | Just parentStyle <- psParentStyle style
1014− = getParentStyleValue field (snd parentStyle)
1115+ = getParentStyleValue field parentStyle
1015getParentStyleValue _ _ = Nothing
1116getParentStyleValue _ _ = Nothing
1017−getParStyleField :: (ParStyleData -> Maybe a) -> ParStyleMap -> [String] ->
1118+getParStyleField :: (ParStyle -> Maybe a) -> [ParStyle] -> Maybe a
1019−getParStyleField field stylemap styles
1119+getParStyleField field styles
1020− | x <- mapMaybe (\x -> M.lookup x stylemap) styles
1021− , (y:_) <- mapMaybe (getParentStyleValue field) x
1120+ | (y:_) <- mapMaybe (getParentStyleValue field) styles
1022 = Just y
1121 = Just y
1023−getParStyleField _ _ _ = Nothing
1122+getParStyleField _ _ = Nothing
1025getTrackedChange :: NameSpaces -> Element -> Maybe TrackedChange
1124getTrackedChange :: NameSpaces -> Element -> Maybe TrackedChange
1026getTrackedChange ns element
1125getTrackedChange ns element
@@ -1042,10 +1141,10 @@ elemToParagraphStyle ns element sty
1042 | Just pPr <- findChildByName ns "w" "pPr" element =
1141 | Just pPr <- findChildByName ns "w" "pPr" element =
1043 let style =
1142 let style =
1044 mapMaybe
1143 mapMaybe
1045− (findAttrByName ns "w" "val")
1144+ (fmap ParaStyleId . findAttrByName ns "w" "val")
1046 (findChildrenByName ns "w" "pStyle" pPr)
1145 (findChildrenByName ns "w" "pStyle" pPr)
1047 in ParagraphStyle
1146 in ParagraphStyle
1048− {pStyle = style
1147+ {pStyle = mapMaybe (`M.lookup` sty) style
1049 , indentation =
1148 , indentation =
1050 findChildByName ns "w" "ind" pPr >>=
1149 findChildByName ns "w" "ind" pPr >>=
1051 elemToParIndentation ns
1150 elemToParIndentation ns
@@ -1057,9 +1156,6 @@ elemToParagraphStyle ns element sty
1057 Just "none" -> False
1156 Just "none" -> False
1058 Just _ -> True
1157 Just _ -> True
1059 Nothing -> False
1158 Nothing -> False
1060− , pHeading = getParStyleField headingLev sty style
1061− , pNumInfo = getParStyleField numInfo sty style
1062− , pBlockQuote = getParStyleField isBlockQuote sty style
1063 , pChange = findChildByName ns "w" "rPr" pPr >>=
1159 , pChange = findChildByName ns "w" "rPr" pPr >>=
1064 filterChild (\e -> isElem ns "w" "ins" e ||
1160 filterChild (\e -> isElem ns "w" "ins" e ||
1065 isElem ns "w" "moveTo" e ||
1161 isElem ns "w" "moveTo" e ||
@@ -1089,16 +1185,20 @@ elemToRunStyleD :: NameSpaces -> Element -> D RunStyle
1089elemToRunStyleD ns element
1185elemToRunStyleD ns element
1090 | Just rPr <- findChildByName ns "w" "rPr" element = do
1186 | Just rPr <- findChildByName ns "w" "rPr" element = do
1091 charStyles <- asks envCharStyles
1187 charStyles <- asks envCharStyles
1092− let parentSty = case
1188+ let parentSty =
1093 findChildByName ns "w" "rStyle" rPr >>=
1189 findChildByName ns "w" "rStyle" rPr >>=
1094− findAttrByName ns "w" "val"
1190+ findAttrByName ns "w" "val" >>=
1096− Just styName | Just style <- M.lookup styName charStyles ->
1191+ flip M.lookup charStyles . CharStyleId
1097− Just (styName, style)
1099 return $ elemToRunStyle ns element parentSty
1192 return $ elemToRunStyle ns element parentSty
1100elemToRunStyleD _ _ = return defaultRunStyle
1193elemToRunStyleD _ _ = return defaultRunStyle
1195+elemToCharStyle :: NameSpaces
1196+ -> Element -> Maybe CharStyle -> Maybe CharStyle
1197+elemToCharStyle ns element parentStyle
1198+ = CharStyle <$> (CharStyleId <$> findAttrByName ns "w" "styleId" element)
1199+ <*> getElementStyleName ns element
1200+ <*> (Just $ elemToRunStyle ns element parentStyle)
1102elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
1202elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
1103elemToRunStyle ns element parentStyle
1203elemToRunStyle ns element parentStyle
1104 | Just rPr <- findChildByName ns "w" "rPr" element =
1204 | Just rPr <- findChildByName ns "w" "rPr" element =
@@ -1121,38 +1221,23 @@ elemToRunStyle ns element parentStyle
1121 , rUnderline =
1221 , rUnderline =
1122 findChildByName ns "w" "u" rPr >>=
1222 findChildByName ns "w" "u" rPr >>=
1123 findAttrByName ns "w" "val"
1223 findAttrByName ns "w" "val"
1124− , rStyle = parentStyle
1224+ , rParentStyle = parentStyle
1126elemToRunStyle _ _ _ = defaultRunStyle
1226elemToRunStyle _ _ _ = defaultRunStyle
1128−getHeaderLevel :: NameSpaces -> Element -> Maybe (String,Int)
1228+getHeaderLevel :: NameSpaces -> Element -> Maybe (ParaStyleName, Int)
1129getHeaderLevel ns element
1229getHeaderLevel ns element
1130− | Just styleId <- findAttrByName ns "w" "styleId" element
1230+ | Just styleName <- getElementStyleName ns element
1131− , Just index <- stripPrefix "Heading" styleId
1132− , Just n <- stringToInteger index
1231+ , Just n <- stringToInteger =<<
1133− , n > 0 = Just (styleId, fromInteger n)
1134− | Just styleId <- findAttrByName ns "w" "styleId" element
1135− , Just index <- findChildByName ns "w" "name" element >>=
1136− findAttrByName ns "w" "val" >>=
1137− stripPrefix "heading "
1232+ (stripPrefix "heading " . map toLower $
1138− , Just n <- stringToInteger index
1233+ fromStyleName styleName)
1139− , n > 0 = Just (styleId, fromInteger n)
1234+ , n > 0 = Just (styleName, fromInteger n)
1140getHeaderLevel _ _ = Nothing
1235getHeaderLevel _ _ = Nothing
1142−blockQuoteStyleIds :: [String]
1143−blockQuoteStyleIds = ["Quote", "BlockQuote", "BlockQuotation"]
1145−blockQuoteStyleNames :: [String]
1146−blockQuoteStyleNames = ["Quote", "Block Text"]
1148−getBlockQuote :: NameSpaces -> Element -> Maybe Bool
1237+getElementStyleName :: Coercible String a => NameSpaces -> Element -> Maybe a
1149−getBlockQuote ns element
1238+getElementStyleName ns el = coerce <$>
1150− | Just styleId <- findAttrByName ns "w" "styleId" element
1151− , styleId `elem` blockQuoteStyleIds = Just True
1152− | Just styleName <- findChildByName ns "w" "name" element >>=
1153− findAttrByName ns "w" "val"
1239+ ((findChildByName ns "w" "name" el >>= findAttrByName ns "w" "val")
1154− , styleName `elem` blockQuoteStyleNames = Just True
1240+ <|> findAttrByName ns "w" "styleId" el)
1155−getBlockQuote _ _ = Nothing
1157getNumInfo :: NameSpaces -> Element -> Maybe (String, String)
1242getNumInfo :: NameSpaces -> Element -> Maybe (String, String)
1158getNumInfo ns element = do
1243getNumInfo ns element = do
@@ -1167,15 +1252,19 @@ getNumInfo ns element = do
1167 return (numId, lvl)
1252 return (numId, lvl)
1170−elemToParStyleData :: NameSpaces -> Element -> Maybe ParStyle -> ParStyleData
1255+elemToParStyleData :: NameSpaces -> Element -> Maybe ParStyle -> Maybe ParStyle
1171−elemToParStyleData ns element parentStyle =
1256+elemToParStyleData ns element parentStyle
1172− ParStyleData
1257+ | Just styleId <- findAttrByName ns "w" "styleId" element
1258+ , Just styleName <- getElementStyleName ns element
1174 headingLev = getHeaderLevel ns element
1261 headingLev = getHeaderLevel ns element
1175− , isBlockQuote = getBlockQuote ns element
1176 , numInfo = getNumInfo ns element
1262 , numInfo = getNumInfo ns element
1177− , psStyle = parentStyle
1263+ , psParentStyle = parentStyle
1264+ , pStyleName = styleName
1265+ , pStyleId = ParaStyleId styleId
1267+elemToParStyleData _ _ _ = Nothing
1180elemToRunElem :: NameSpaces -> Element -> D RunElem
1269elemToRunElem :: NameSpaces -> Element -> D RunElem
1181elemToRunElem ns element
1270elemToRunElem ns element