git.iko.soy/typeable/pandoc
on master help sign in
OpenDocument Writer: Fixed handling of spaces and tabs in preformatted blocks.
5eb204cfiddlosopher
Text/Pandoc/Writers/OpenDocument.hs+25−11
@@ -36,7 +36,8 @@ import Text.Pandoc.XML
36import Text.Pandoc.Readers.TeXMath
36import Text.Pandoc.Readers.TeXMath
37import Text.PrettyPrint.HughesPJ hiding ( Str )
37import Text.PrettyPrint.HughesPJ hiding ( Str )
38
38
39−import Control.Applicative ((<$>))
39+import Control.Applicative ( (<$>) )
40+import Control.Arrow ( (***), (>>>) )
40import Control.Monad.State hiding ( when )
41import Control.Monad.State hiding ( when )
41import Data.Char (chr)
42import Data.Char (chr)
42
43
@@ -68,6 +69,9 @@ defaultWriterState =
68 , inDefinition = False
69 , inDefinition = False
69 }
70 }
70
71
72+when :: Bool -> Doc -> Doc
73+when p a = if p then a else empty
74+
71addTableStyle :: Doc -> State WriterState ()
75addTableStyle :: Doc -> State WriterState ()
72addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s }
76addTableStyle i = modify $ \s -> s { stTableStyles = i : stTableStyles s }
73
77
@@ -103,6 +107,19 @@ inQuotes :: QuoteType -> Doc -> Doc
103inQuotes SingleQuote s = text "&#8216;" <> s <> text "&#8217;"
107inQuotes SingleQuote s = text "&#8216;" <> s <> text "&#8217;"
104inQuotes DoubleQuote s = text "&#8220;" <> s <> text "&#8221;"
108inQuotes DoubleQuote s = text "&#8220;" <> s <> text "&#8221;"
105
109
110+handleSpaces :: String -> Doc
111+handleSpaces s
112+ | ( ' ':_) <- s = genTag s
113+ | ('\t':x) <- s = selfClosingTag "text:tab" [] <> rm x
114+ | otherwise = rm s
115+ where
116+ genTag = span (==' ') >>> tag . length *** rm >>> uncurry (<>)
117+ tag n = when (n /= 0) $ selfClosingTag "text:s" [("text:c", show n)]
118+ rm ( ' ':xs) = char ' ' <> genTag xs
119+ rm ('\t':xs) = selfClosingTag "text:tab" [] <> genTag xs
120+ rm ( x:xs) = char x <> rm xs
121+ rm [] = empty
122+
106-- | Convert list of authors to a docbook <author> section
123-- | Convert list of authors to a docbook <author> section
107authorToOpenDocument :: [Char] -> Doc
124authorToOpenDocument :: [Char] -> Doc
108authorToOpenDocument name =
125authorToOpenDocument name =
@@ -125,8 +142,7 @@ authorToOpenDocument name =
125-- | Convert Pandoc document to string in OpenDocument format.
142-- | Convert Pandoc document to string in OpenDocument format.
126writeOpenDocument :: WriterOptions -> Pandoc -> String
143writeOpenDocument :: WriterOptions -> Pandoc -> String
127writeOpenDocument opts (Pandoc (Meta title authors date) blocks) =
144writeOpenDocument opts (Pandoc (Meta title authors date) blocks) =
128− let when p a = if p then a else empty
129− root = inTags True "office:document-content" openDocumentNameSpaces
145+ let root = inTags True "office:document-content" openDocumentNameSpaces
130 header = when (writerStandalone opts) $ text (writerHeader opts)
146 header = when (writerStandalone opts) $ text (writerHeader opts)
131 title' = case runState (wrap opts title) defaultWriterState of
147 title' = case runState (wrap opts title) defaultWriterState of
132 (t,_) -> if isEmpty t then empty else inHeaderTags 1 t
148 (t,_) -> if isEmpty t then empty else inHeaderTags 1 t
@@ -136,7 +152,6 @@ writeOpenDocument opts (Pandoc (Meta title authors date) blocks) =
136 before = writerIncludeBefore opts
152 before = writerIncludeBefore opts
137 after = writerIncludeAfter opts
153 after = writerIncludeAfter opts
138 (doc, s) = runState (blocksToOpenDocument opts blocks) defaultWriterState
154 (doc, s) = runState (blocksToOpenDocument opts blocks) defaultWriterState
139−
140 body = (if null before then empty else text before) $$
155 body = (if null before then empty else text before) $$
141 doc $$
156 doc $$
142 (if null after then empty else text after)
157 (if null after then empty else text after)
@@ -158,7 +173,7 @@ withParagraphStyle _ _ [] = return empty
158inPreformattedTags :: String -> State WriterState Doc
173inPreformattedTags :: String -> State WriterState Doc
159inPreformattedTags s = do
174inPreformattedTags s = do
160 n <- paraStyle "Preformatted_20_Text" []
175 n <- paraStyle "Preformatted_20_Text" []
161− return . inParagraphTagsWithStyle ("P" ++ show n) . text $ s
176+ return . inParagraphTagsWithStyle ("P" ++ show n) . handleSpaces $ s
162
177
163orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc
178orderedListToOpenDocument :: WriterOptions -> Int -> [[Block]] -> State WriterState Doc
164orderedListToOpenDocument o pn bs =
179orderedListToOpenDocument o pn bs =
@@ -212,7 +227,7 @@ inBlockQuote o i (b:bs)
212 go ni =<< inBlockQuote o ni l
227 go ni =<< inBlockQuote o ni l
213 | Para l <- b = do go i =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
228 | Para l <- b = do go i =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
214 | otherwise = do go i =<< blockToOpenDocument o b
229 | otherwise = do go i =<< blockToOpenDocument o b
215− where go ni block = ($$) block <$> inBlockQuote o ni bs
230+ where go ni block = ($$) block <$> inBlockQuote o ni bs
216inBlockQuote _ _ [] = resetIndent >> return empty
231inBlockQuote _ _ [] = resetIndent >> return empty
217
232
218-- | Convert a list of Pandoc blocks to OpenDocument.
233-- | Convert a list of Pandoc blocks to OpenDocument.
@@ -306,7 +321,7 @@ inlineToOpenDocument o ils
306 | Apostrophe <- ils = return $ text "&#8217;"
321 | Apostrophe <- ils = return $ text "&#8217;"
307 | Space <- ils = return $ char ' '
322 | Space <- ils = return $ char ' '
308 | LineBreak <- ils = return $ selfClosingTag "text:line-break" []
323 | LineBreak <- ils = return $ selfClosingTag "text:line-break" []
309− | Str s <- ils = return $ text $ escapeStringForXML s
324+ | Str s <- ils = return $ handleSpaces $ escapeStringForXML s
310 | Emph l <- ils = inSpanTags "Emphasis" <$> inlinesToOpenDocument o l
325 | Emph l <- ils = inSpanTags "Emphasis" <$> inlinesToOpenDocument o l
311 | Strong l <- ils = inSpanTags "Strong_20_Emphasis" <$> inlinesToOpenDocument o l
326 | Strong l <- ils = inSpanTags "Strong_20_Emphasis" <$> inlinesToOpenDocument o l
312 | Strikeout l <- ils = inSpanTags "Strikeout" <$> inlinesToOpenDocument o l
327 | Strikeout l <- ils = inSpanTags "Strikeout" <$> inlinesToOpenDocument o l
@@ -322,7 +337,7 @@ inlineToOpenDocument o ils
322 | Note l <- ils = mkNote l
337 | Note l <- ils = mkNote l
323 | otherwise = return empty
338 | otherwise = return empty
324 where
339 where
325− preformatted = return . inSpanTags "Teletype" . text . escapeStringForXML
340+ preformatted = return . inSpanTags "Teletype" . handleSpaces . escapeStringForXML
326 mkLink s t = inTags False "text:a" [ ("xlink:type" , "simple")
341 mkLink s t = inTags False "text:a" [ ("xlink:type" , "simple")
327 , ("xlink:href" , s )
342 , ("xlink:href" , s )
328 , ("office:name", t )
343 , ("office:name", t )
@@ -419,9 +434,8 @@ paraStyle parent attrs = do
419 , ("style:family" , "paragraph" )
434 , ("style:family" , "paragraph" )
420 , ("style:parent-style-name", parent )]
435 , ("style:parent-style-name", parent )]
421 indentVal = flip (++) "in" . show $ if b then (max 0.5 i) else i
436 indentVal = flip (++) "in" . show $ if b then (max 0.5 i) else i
422− indent = if i == 0 && not b
437+ indent = when (i /= 0 || b) $
423− then empty
424− else selfClosingTag "style:paragraph-properties"
438+ selfClosingTag "style:paragraph-properties"
425 [ ("fo:margin-left" , indentVal)
439 [ ("fo:margin-left" , indentVal)
426 , ("fo:margin-right" , "0in" )
440 , ("fo:margin-right" , "0in" )
427 , ("fo:text-indent" , "0in" )
441 , ("fo:text-indent" , "0in" )