@@ -55,6 +55,8 @@ module Text.Pandoc.Shared (
55 normalizeSpaces,
55 normalizeSpaces,
56 extractSpaces,
56 extractSpaces,
57 normalize,
57 normalize,
58 stringify,
60 stringify,
59 compactify,
61 compactify,
60 compactify',
62 compactify',
@@ -84,7 +86,6 @@ module Text.Pandoc.Shared (
85import Text.Pandoc.Definition
87import Text.Pandoc.Definition
86import Text.Pandoc.Walk
88import Text.Pandoc.Walk
87−import Text.Pandoc.Generic
88import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..))
89import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..))
89import qualified Text.Pandoc.Builder as B
90import qualified Text.Pandoc.Builder as B
90import qualified Text.Pandoc.UTF8 as UTF8
91import qualified Text.Pandoc.UTF8 as UTF8
@@ -350,72 +351,142 @@ extractSpaces f is =
350-- | Normalize @Pandoc@ document, consolidating doubled 'Space's,
351-- | Normalize @Pandoc@ document, consolidating doubled 'Space's,
351-- combining adjacent 'Str's and 'Emph's, remove 'Null's and
352-- combining adjacent 'Str's and 'Emph's, remove 'Null's and
352-- empty elements, etc.
353-- empty elements, etc.
353−normalize :: (Eq a, Data a) => a -> a
354+normalize :: Pandoc -> Pandoc
354−normalize = topDown removeEmptyBlocks .
355+normalize (Pandoc (Meta meta) blocks) =
355− topDown consolidateInlines .
356+ Pandoc (Meta $ M.map go meta) (normalizeBlocks blocks)
356− bottomUp (removeEmptyInlines . removeTrailingInlineSpaces)
357+ where go (MetaInlines xs) = MetaInlines $ normalizeInlines xs
357−
358+ go (MetaBlocks xs) = MetaBlocks $ normalizeBlocks xs
358−removeEmptyBlocks :: [Block] -> [Block]
359+ go (MetaList ms) = MetaList $ map go ms
359−removeEmptyBlocks (Null : xs) = removeEmptyBlocks xs
360+ go (MetaMap m) = MetaMap $ M.map go m
360−removeEmptyBlocks (BulletList [] : xs) = removeEmptyBlocks xs
361+ go x = x
361−removeEmptyBlocks (OrderedList _ [] : xs) = removeEmptyBlocks xs
362+
362−removeEmptyBlocks (DefinitionList [] : xs) = removeEmptyBlocks xs
363+normalizeBlocks :: [Block] -> [Block]
363−removeEmptyBlocks (RawBlock _ [] : xs) = removeEmptyBlocks xs
364+normalizeBlocks (Null : xs) = normalizeBlocks xs
364−removeEmptyBlocks (x:xs) = x : removeEmptyBlocks xs
365+normalizeBlocks (Div attr bs : xs) =
365−removeEmptyBlocks [] = []
366+ Div attr (normalizeBlocks bs) : normalizeBlocks xs
366−
367+normalizeBlocks (BlockQuote bs : xs) =
367−removeEmptyInlines :: [Inline] -> [Inline]
368+ case normalizeBlocks bs of
368−removeEmptyInlines (Emph [] : zs) = removeEmptyInlines zs
369+ [] -> normalizeBlocks xs
369−removeEmptyInlines (Strong [] : zs) = removeEmptyInlines zs
370+ bs' -> BlockQuote bs' : normalizeBlocks xs
370−removeEmptyInlines (Subscript [] : zs) = removeEmptyInlines zs
371+normalizeBlocks (BulletList [] : xs) = normalizeBlocks xs
371−removeEmptyInlines (Superscript [] : zs) = removeEmptyInlines zs
372+normalizeBlocks (BulletList items : xs) =
372−removeEmptyInlines (SmallCaps [] : zs) = removeEmptyInlines zs
373+ BulletList (map normalizeBlocks items) : normalizeBlocks xs
373−removeEmptyInlines (Strikeout [] : zs) = removeEmptyInlines zs
374+normalizeBlocks (OrderedList _ [] : xs) = normalizeBlocks xs
374−removeEmptyInlines (RawInline _ [] : zs) = removeEmptyInlines zs
375+normalizeBlocks (OrderedList attr items : xs) =
375−removeEmptyInlines (Code _ [] : zs) = removeEmptyInlines zs
376+ OrderedList attr (map normalizeBlocks items) : normalizeBlocks xs
376−removeEmptyInlines (Str "" : zs) = removeEmptyInlines zs
377+normalizeBlocks (DefinitionList [] : xs) = normalizeBlocks xs
377−removeEmptyInlines (x : xs) = x : removeEmptyInlines xs
378+normalizeBlocks (DefinitionList items : xs) =
378−removeEmptyInlines [] = []
379+ DefinitionList (map go items) : normalizeBlocks xs
379−
380+ where go (ils, bs) = (normalizeInlines ils, map normalizeBlocks bs)
380−removeTrailingInlineSpaces :: [Inline] -> [Inline]
381+normalizeBlocks (RawBlock _ "" : xs) = normalizeBlocks xs
381−removeTrailingInlineSpaces = reverse . removeLeadingInlineSpaces . reverse
382+normalizeBlocks (Para ils : xs) =
382−
383+ case normalizeInlines ils of
383−removeLeadingInlineSpaces :: [Inline] -> [Inline]
384+ [] -> normalizeBlocks xs
384−removeLeadingInlineSpaces = dropWhile isSpaceOrEmpty
385+ ils' -> Para ils' : normalizeBlocks xs
385−
386+normalizeBlocks (Plain ils : xs) =
386−consolidateInlines :: [Inline] -> [Inline]
387+ case normalizeInlines ils of
387−consolidateInlines (Str x : ys) =
388+ [] -> normalizeBlocks xs
389+ ils' -> Plain ils' : normalizeBlocks xs
390+normalizeBlocks (Header lev attr ils : xs) =
391+ Header lev attr (normalizeInlines ils) : normalizeBlocks xs
392+normalizeBlocks (Table capt aligns widths hdrs rows : xs) =
393+ Table (normalizeInlines capt) aligns widths
394+ (map normalizeBlocks hdrs) (map (map normalizeBlocks) rows)
395+ : normalizeBlocks xs
396+normalizeBlocks (x:xs) = x : normalizeBlocks xs
397+normalizeBlocks [] = []
399+normalizeInlines :: [Inline] -> [Inline]
400+normalizeInlines (Str x : ys) =
388 case concat (x : map fromStr strs) of
401 case concat (x : map fromStr strs) of
389− "" -> consolidateInlines rest
402+ "" -> rest
390− n -> Str n : consolidateInlines rest
403+ n -> Str n : rest
392− (strs, rest) = span isStr ys
405+ (strs, rest) = span isStr $ normalizeInlines ys
393 isStr (Str _) = True
406 isStr (Str _) = True
394 isStr _ = False
407 isStr _ = False
395 fromStr (Str z) = z
408 fromStr (Str z) = z
396− fromStr _ = error "consolidateInlines - fromStr - not a Str"
409+ fromStr _ = error "normalizeInlines - fromStr - not a Str"
397−consolidateInlines (Space : ys) = Space : rest
410+normalizeInlines (Space : ys) =
398 where isSp Space = True
414 where isSp Space = True
399 isSp _ = False
415 isSp _ = False
400− rest = consolidateInlines $ dropWhile isSp ys
416+ rest = dropWhile isSp $ normalizeInlines ys
401−consolidateInlines (Emph xs : Emph ys : zs) = consolidateInlines $
417+normalizeInlines (Emph xs : zs) =
418+ case normalizeInlines zs of
419+ (Emph ys : rest) -> normalizeInlines $
402− Emph (xs ++ ys) : zs
420+ Emph (normalizeInlines $ xs ++ ys) : rest
403−consolidateInlines (Strong xs : Strong ys : zs) = consolidateInlines $
421+ rest -> case normalizeInlines xs of
404− Strong (xs ++ ys) : zs
422+ [] -> rest
405−consolidateInlines (Subscript xs : Subscript ys : zs) = consolidateInlines $
423+ xs' -> Emph xs' : rest
406− Subscript (xs ++ ys) : zs
424+normalizeInlines (Strong xs : zs) =
407−consolidateInlines (Superscript xs : Superscript ys : zs) = consolidateInlines $
425+ case normalizeInlines zs of
408− Superscript (xs ++ ys) : zs
426+ (Strong ys : rest) -> normalizeInlines $
409−consolidateInlines (SmallCaps xs : SmallCaps ys : zs) = consolidateInlines $
427+ Strong (normalizeInlines $ xs ++ ys) : rest
410− SmallCaps (xs ++ ys) : zs
428+ rest -> case normalizeInlines xs of
411−consolidateInlines (Strikeout xs : Strikeout ys : zs) = consolidateInlines $
429+ [] -> rest
412− Strikeout (xs ++ ys) : zs
430+ xs' -> Strong xs' : rest
413−consolidateInlines (RawInline f x : RawInline f' y : zs) | f == f' =
431+normalizeInlines (Subscript xs : zs) =
414− consolidateInlines $ RawInline f (x ++ y) : zs
432+ case normalizeInlines zs of
415−consolidateInlines (Code a1 x : Code a2 y : zs) | a1 == a2 =
433+ (Subscript ys : rest) -> normalizeInlines $
416− consolidateInlines $ Code a1 (x ++ y) : zs
434+ Subscript (normalizeInlines $ xs ++ ys) : rest
417−consolidateInlines (x : xs) = x : consolidateInlines xs
435+ rest -> case normalizeInlines xs of
418−consolidateInlines [] = []
436+ [] -> rest
437+ xs' -> Subscript xs' : rest
438+normalizeInlines (Superscript xs : zs) =
439+ case normalizeInlines zs of
440+ (Superscript ys : rest) -> normalizeInlines $
441+ Superscript (normalizeInlines $ xs ++ ys) : rest
442+ rest -> case normalizeInlines xs of
444+ xs' -> Superscript xs' : rest
445+normalizeInlines (SmallCaps xs : zs) =
446+ case normalizeInlines zs of
447+ (SmallCaps ys : rest) -> normalizeInlines $
448+ SmallCaps (normalizeInlines $ xs ++ ys) : rest
449+ rest -> case normalizeInlines xs of
451+ xs' -> SmallCaps xs' : rest
452+normalizeInlines (Strikeout xs : zs) =
453+ case normalizeInlines zs of
454+ (Strikeout ys : rest) -> normalizeInlines $
455+ Strikeout (normalizeInlines $ xs ++ ys) : rest
456+ rest -> case normalizeInlines xs of
458+ xs' -> Strikeout xs' : rest
459+normalizeInlines (RawInline _ [] : ys) = normalizeInlines ys
460+normalizeInlines (RawInline f xs : zs) =
461+ case normalizeInlines zs of
462+ (RawInline f' ys : rest) | f == f' -> normalizeInlines $
463+ RawInline f (xs ++ ys) : rest
464+ rest -> RawInline f xs : rest
465+normalizeInlines (Code _ "" : ys) = normalizeInlines ys
466+normalizeInlines (Code attr xs : zs) =
467+ case normalizeInlines zs of
468+ (Code attr' ys : rest) | attr == attr' -> normalizeInlines $
469+ Code attr (xs ++ ys) : rest
470+ rest -> Code attr xs : rest
471+-- allow empty spans, they may carry identifiers etc.
472+-- normalizeInlines (Span _ [] : ys) = normalizeInlines ys
473+normalizeInlines (Span attr xs : zs) =
474+ case normalizeInlines zs of
475+ (Span attr' ys : rest) | attr == attr' -> normalizeInlines $
476+ Span attr (normalizeInlines $ xs ++ ys) : rest
477+ rest -> Span attr (normalizeInlines xs) : rest
478+normalizeInlines (Note bs : ys) = Note (normalizeBlocks bs) :
480+normalizeInlines (Quoted qt ils : ys) =
481+ Quoted qt (normalizeInlines ils) : normalizeInlines ys
482+normalizeInlines (Link ils t : ys) =
483+ Link (normalizeInlines ils) t : normalizeInlines ys
484+normalizeInlines (Image ils t : ys) =
485+ Image (normalizeInlines ils) t : normalizeInlines ys
486+normalizeInlines (Cite cs ils : ys) =
487+ Cite cs (normalizeInlines ils) : normalizeInlines ys
488+normalizeInlines (x : xs) = x : normalizeInlines xs
489+normalizeInlines [] = []
420-- | Convert pandoc structure to a string with formatting removed.
491-- | Convert pandoc structure to a string with formatting removed.
421-- Footnotes are skipped (since we don't want their contents in link
492-- Footnotes are skipped (since we don't want their contents in link