Blame src/Text/Pandoc/Readers/Docx/Combine.hs

Packit Service d2f85f
{-# LANGUAGE FlexibleInstances    #-}
Packit Service d2f85f
{-# LANGUAGE PatternGuards        #-}
Packit Service d2f85f
{-# LANGUAGE TypeSynonymInstances #-}
Packit Service d2f85f
Packit Service d2f85f
module Text.Pandoc.Readers.Docx.Combine ( smushInlines
Packit Service d2f85f
                                        , smushBlocks
Packit Service d2f85f
                                        )
Packit Service d2f85f
       where
Packit Service d2f85f
Packit Service d2f85f
import Data.List
Packit Service d2f85f
import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
Packit Service d2f85f
import qualified Data.Sequence as Seq (null)
Packit Service d2f85f
import Text.Pandoc.Builder
Packit Service d2f85f
Packit Service d2f85f
data Modifier a = Modifier (a -> a)
Packit Service d2f85f
                | AttrModifier (Attr -> a -> a) Attr
Packit Service d2f85f
                | NullModifier
Packit Service d2f85f
Packit Service d2f85f
spaceOutInlinesL :: Inlines -> (Inlines, Inlines)
Packit Service d2f85f
spaceOutInlinesL ms = (l, stackInlines fs (m' <> r))
Packit Service d2f85f
  where (l, m, r) = spaceOutInlines ms
Packit Service d2f85f
        (fs, m')  = unstackInlines m
Packit Service d2f85f
Packit Service d2f85f
spaceOutInlinesR :: Inlines -> (Inlines, Inlines)
Packit Service d2f85f
spaceOutInlinesR ms = (stackInlines fs (l <> m'), r)
Packit Service d2f85f
  where (l, m, r) = spaceOutInlines ms
Packit Service d2f85f
        (fs, m')  = unstackInlines m
Packit Service d2f85f
Packit Service d2f85f
spaceOutInlines :: Inlines -> (Inlines, Inlines, Inlines)
Packit Service d2f85f
spaceOutInlines ils =
Packit Service d2f85f
  let (fs, ils') = unstackInlines ils
Packit Service d2f85f
      contents = unMany ils'
Packit Service d2f85f
      left  = case viewl contents of
Packit Service d2f85f
        (Space :< _) -> space
Packit Service d2f85f
        _            -> mempty
Packit Service d2f85f
      right = case viewr contents of
Packit Service d2f85f
        (_ :> Space) -> space
Packit Service d2f85f
        _            -> mempty in
Packit Service d2f85f
  (left, stackInlines fs $ trimInlines . Many $ contents, right)
Packit Service d2f85f
Packit Service d2f85f
stackInlines :: [Modifier Inlines] -> Inlines -> Inlines
Packit Service d2f85f
stackInlines [] ms = ms
Packit Service d2f85f
stackInlines (NullModifier : fs) ms = stackInlines fs ms
Packit Service d2f85f
stackInlines (Modifier f : fs) ms =
Packit Service d2f85f
  if isEmpty ms
Packit Service d2f85f
  then stackInlines fs ms
Packit Service d2f85f
  else f $ stackInlines fs ms
Packit Service d2f85f
stackInlines (AttrModifier f attr : fs) ms = f attr $ stackInlines fs ms
Packit Service d2f85f
Packit Service d2f85f
unstackInlines :: Inlines -> ([Modifier Inlines], Inlines)
Packit Service d2f85f
unstackInlines ms = case ilModifier ms of
Packit Service d2f85f
  NullModifier -> ([], ms)
Packit Service d2f85f
  _            -> (f : fs, ms') where
Packit Service d2f85f
    f = ilModifier ms
Packit Service d2f85f
    (fs, ms') = unstackInlines $ ilInnards ms
Packit Service d2f85f
Packit Service d2f85f
ilModifier :: Inlines -> Modifier Inlines
Packit Service d2f85f
ilModifier ils = case viewl (unMany ils) of
Packit Service d2f85f
  (x :< xs) | Seq.null xs -> case x of
Packit Service d2f85f
    (Emph _)          -> Modifier emph
Packit Service d2f85f
    (Strong _)        -> Modifier strong
Packit Service d2f85f
    (SmallCaps _)     -> Modifier smallcaps
Packit Service d2f85f
    (Strikeout _)     -> Modifier strikeout
Packit Service d2f85f
    (Superscript _)   -> Modifier superscript
Packit Service d2f85f
    (Subscript _)     -> Modifier subscript
Packit Service d2f85f
    (Link attr _ tgt) -> Modifier $ linkWith attr (fst tgt) (snd tgt)
Packit Service d2f85f
    (Span attr _)     -> AttrModifier spanWith attr
Packit Service d2f85f
    _                 -> NullModifier
Packit Service d2f85f
  _ -> NullModifier
Packit Service d2f85f
Packit Service d2f85f
ilInnards :: Inlines -> Inlines
Packit Service d2f85f
ilInnards ils = case viewl (unMany ils) of
Packit Service d2f85f
  (x :< xs) | Seq.null xs -> case x of
Packit Service d2f85f
    (Emph lst)        -> fromList lst
Packit Service d2f85f
    (Strong lst)      -> fromList lst
Packit Service d2f85f
    (SmallCaps lst)   -> fromList lst
Packit Service d2f85f
    (Strikeout lst)   -> fromList lst
Packit Service d2f85f
    (Superscript lst) -> fromList lst
Packit Service d2f85f
    (Subscript lst)   -> fromList lst
Packit Service d2f85f
    (Link _ lst _)    -> fromList lst
Packit Service d2f85f
    (Span _ lst)      -> fromList lst
Packit Service d2f85f
    _                 -> ils
Packit Service d2f85f
  _          -> ils
Packit Service d2f85f
Packit Service d2f85f
inlinesL :: Inlines -> (Inlines, Inlines)
Packit Service d2f85f
inlinesL ils = case viewl $ unMany ils of
Packit Service d2f85f
  (s :< sq) -> (singleton s, Many sq)
Packit Service d2f85f
  _         -> (mempty, ils)
Packit Service d2f85f
Packit Service d2f85f
inlinesR :: Inlines -> (Inlines, Inlines)
Packit Service d2f85f
inlinesR ils = case viewr $ unMany ils of
Packit Service d2f85f
  (sq :> s) -> (Many sq, singleton s)
Packit Service d2f85f
  _         -> (ils, mempty)
Packit Service d2f85f
Packit Service d2f85f
combineInlines :: Inlines -> Inlines -> Inlines
Packit Service d2f85f
combineInlines x y =
Packit Service d2f85f
  let (xs', x') = inlinesR x
Packit Service d2f85f
      (y', ys') = inlinesL y
Packit Service d2f85f
  in
Packit Service d2f85f
   xs' <> combineSingletonInlines x' y' <> ys'
Packit Service d2f85f
Packit Service d2f85f
combineSingletonInlines :: Inlines -> Inlines -> Inlines
Packit Service d2f85f
combineSingletonInlines x y =
Packit Service d2f85f
  let (xfs, xs) = unstackInlines x
Packit Service d2f85f
      (yfs, ys) = unstackInlines y
Packit Service d2f85f
      shared = xfs `intersect` yfs
Packit Service d2f85f
      x_remaining = xfs \\ shared
Packit Service d2f85f
      y_remaining = yfs \\ shared
Packit Service d2f85f
      x_rem_attr = filter isAttrModifier x_remaining
Packit Service d2f85f
      y_rem_attr = filter isAttrModifier y_remaining
Packit Service d2f85f
  in
Packit Service d2f85f
   case null shared of
Packit Service d2f85f
     True | isEmpty xs && isEmpty ys ->
Packit Service d2f85f
            stackInlines (x_rem_attr ++ y_rem_attr) mempty
Packit Service d2f85f
          | isEmpty xs ->
Packit Service d2f85f
            let (sp, y') = spaceOutInlinesL y in
Packit Service d2f85f
            stackInlines x_rem_attr mempty <> sp <> y'
Packit Service d2f85f
          | isEmpty ys ->
Packit Service d2f85f
            let (x', sp) = spaceOutInlinesR x in
Packit Service d2f85f
            x' <> sp <> stackInlines y_rem_attr mempty
Packit Service d2f85f
          | otherwise ->
Packit Service d2f85f
              let (x', xsp) = spaceOutInlinesR x
Packit Service d2f85f
                  (ysp, y') = spaceOutInlinesL y
Packit Service d2f85f
              in
Packit Service d2f85f
               x' <> xsp <> ysp <> y'
Packit Service d2f85f
     False -> stackInlines shared $
Packit Service d2f85f
              combineInlines
Packit Service d2f85f
              (stackInlines x_remaining xs)
Packit Service d2f85f
              (stackInlines y_remaining ys)
Packit Service d2f85f
Packit Service d2f85f
combineBlocks :: Blocks -> Blocks -> Blocks
Packit Service d2f85f
combineBlocks bs cs
Packit Service d2f85f
  | bs' :> BlockQuote bs'' <- viewr (unMany bs)
Packit Service d2f85f
  , BlockQuote cs'' :< cs' <- viewl (unMany cs) =
Packit Service d2f85f
      Many $ (bs' |> BlockQuote (bs'' <> cs'')) >< cs'
Packit Service d2f85f
combineBlocks bs cs = bs <> cs
Packit Service d2f85f
Packit Service d2f85f
instance (Monoid a, Eq a) => Eq (Modifier a) where
Packit Service d2f85f
  (Modifier f) == (Modifier g) = f mempty == g mempty
Packit Service d2f85f
  (AttrModifier f attr) == (AttrModifier g attr') = f attr mempty == g attr' mempty
Packit Service d2f85f
  NullModifier == NullModifier = True
Packit Service d2f85f
  _ == _ = False
Packit Service d2f85f
Packit Service d2f85f
isEmpty :: (Monoid a, Eq a) => a -> Bool
Packit Service d2f85f
isEmpty x = x == mempty
Packit Service d2f85f
Packit Service d2f85f
isAttrModifier :: Modifier a -> Bool
Packit Service d2f85f
isAttrModifier (AttrModifier _ _) = True
Packit Service d2f85f
isAttrModifier _                  = False
Packit Service d2f85f
Packit Service d2f85f
smushInlines :: [Inlines] -> Inlines
Packit Service d2f85f
smushInlines xs = foldl combineInlines mempty xs
Packit Service d2f85f
Packit Service d2f85f
smushBlocks :: [Blocks] -> Blocks
Packit Service d2f85f
smushBlocks xs = foldl combineBlocks mempty xs