packages feed

pro-abstract-0.1.0.0: library/pro-abstract/ProAbstract/Structure/Block.hs

module ProAbstract.Structure.Block
    ( Block (..), paragraph, Blocks (..), Tagged (..)
    ) where

import ProAbstract.Annotation
import ProAbstract.Content
import ProAbstract.Structure.Fork
import ProAbstract.Metadata
import ProAbstract.Structure.CanBePlain
import ProAbstract.Structure.CanFork
import ProAbstract.Structure.HasManyParagraphs
import ProAbstract.Structure.HasManyPlainBlocks
import ProAbstract.Structure.HasManyPlainInlines
import ProAbstract.Structure.Paragraph
import ProAbstract.Structure.Plain
import ProAbstract.Structure.PlainBlock
import ProAbstract.Tag


-- ⭐ Block

data Block ann =
    BlockPlain     (Tagged (PlainBlock ann)) -- ^ 'ProAbstract.plain'
  | BlockParagraph (Paragraph ann)           -- ^ 'ProAbstract.paragraph'
  | BlockFork      (Tagged (Blocks ann))     -- ^ 'ProAbstract.fork'
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable, NFData)

type instance Annotation (Block ann) = ann

type instance Plain (Block ann) = Tagged (PlainBlock ann)

type instance Fork (Block ann) = Tagged (Blocks ann)

instance HasMetadata (Block ann) where
    type MetadataOpticKind (Block ann) = An_AffineTraversal
    metadata = tag % metadata

instance HasManyAnnotations (Block ann) (Block ann') where
    allAnnotations = traversalVL \f -> \case
        BlockPlain     x -> BlockPlain     <$> traverseOf allAnnotations f x
        BlockParagraph x -> BlockParagraph <$> traverseOf allAnnotations f x
        BlockFork      x -> BlockFork      <$> traverseOf allAnnotations f x

instance HasAnnotation (Block ann) (Block ann) where
    annotation = lens f g
      where
        f = \case
            BlockPlain     x -> view annotation x
            BlockParagraph x -> view annotation x
            BlockFork      x -> view annotation x
        g = \case
            BlockPlain     x -> \a -> BlockPlain     (set annotation a x)
            BlockParagraph x -> \a -> BlockParagraph (set annotation a x)
            BlockFork      x -> \a -> BlockFork      (set annotation a x)

instance HasManyPlainInlines (Block ann) where
    allPlainInlines = allParagraphs % allPlainInlines

instance HasManyParagraphs (Block ann) where
    allParagraphs = paragraph `adjoin` (fork % allParagraphs)

instance HasManyPlainBlocks (Block ann) where
    allPlainBlocks = plain `adjoin` (fork % allPlainBlocks)

instance HasTag (Block ann) where
    type TagOpticKind (Block ann) = An_AffineTraversal
    tag = atraversal f g
      where
        f = \case
            BlockPlain x -> Right (view tag x)
            BlockFork  x -> Right (view tag x)
            x -> Left x
        g = \case
            BlockPlain x -> \a -> BlockPlain (set tag a x)
            BlockFork  x -> \a -> BlockFork  (set tag a x)
            x -> \_ -> x

instance HasManyTags (Block ann) where
    allTags = (fork % allTags) `adjoin` (paragraph % allTags) `adjoin` (plain % tag)
    allInlineTags = allParagraphs % allInlineTags

instance HasManyBlockTags (Block ann) where
    allBlockTags = (fork % allBlockTags) `adjoin` (plain % tag)

instance HasWitherableInlineTags (Block ann) where
    witherInlineTags f = traverseOf allParagraphs (witherInlineTags f)

instance HasManyMetadata (Block ann) where
    allMetadata = allTags % metadata

instance CanFork (Block ann) where
    fork = prism'
        BlockFork
        \case{ BlockFork t -> Just t; _ -> Nothing }

instance CanBePlain (Block ann) where
    plain = prism'
        BlockPlain
        \case{ BlockPlain t -> Just t; _ -> Nothing }

paragraph :: Prism' (Block ann) (Paragraph ann)
paragraph = prism'
    BlockParagraph
    \case{ BlockParagraph p -> Just p; _ -> Nothing }


-- ⭐ Blocks

newtype Blocks ann =
    Blocks
      (Seq (Block ann)) -- ^ 'ProAbstract.content'
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable, NFData)
  deriving newtype (Semigroup, Monoid)

type instance Contents (Blocks ann) = Block ann

instance HasContents (Blocks ann) (Blocks ann') where
    contents = castOptic coerced

instance IsList (Blocks ann) where
    type Item (Blocks ann) = Block ann
    toList (Blocks xs) = toList xs
    fromList xs = Blocks (fromList xs)

type instance Annotation (Blocks ann) = ann

instance HasManyAnnotations (Blocks ann) (Blocks ann') where
    allAnnotations = contents % traversed % allAnnotations

instance HasManyPlainInlines (Blocks ann) where
    allPlainInlines = contents % traversed % allPlainInlines

instance HasManyPlainBlocks (Blocks ann) where
    allPlainBlocks = contents % traversed % allPlainBlocks

instance HasManyTags (Blocks ann) where
    allTags = contents % traversed % allTags
    allInlineTags = contents % traversed % allInlineTags

instance HasManyBlockTags (Blocks ann) where
    allBlockTags = contents % traversed % allBlockTags

instance HasManyMetadata (Blocks ann) where
    allMetadata = allTags % metadata

instance HasManyParagraphs (Blocks ann) where
    allParagraphs = contents % traversed % allParagraphs

instance HasWitherableTags (Blocks ann) where
    witherTags f = traverseOf contents $ seqWither \case
        BlockParagraph x ->
            Just . BlockParagraph <$> traverseOf content (witherTags f) x
        BlockPlain x ->
            f (view tag x) >>= \case
                Nothing -> pure Nothing
                Just t -> pure . Just . BlockPlain . set tag t $ x
        BlockFork x ->
            f (view tag x) >>= \case
                Nothing -> pure Nothing
                Just t -> Just . BlockFork . set tag t <$> traverseOf content (witherTags f) x

instance HasWitherableBlockTags (Blocks ann) where
    witherBlockTags f = traverseOf contents $ seqWither \case
        BlockParagraph x -> pure $ Just $ BlockParagraph x
        BlockPlain x ->
            f (view tag x) >>= \case
                Nothing -> pure Nothing
                Just t -> pure . Just . BlockPlain . set tag t $ x
        BlockFork x ->
            f (view tag x) >>= \case
                Nothing -> pure Nothing
                Just t -> Just . BlockFork . set tag t <$> traverseOf content (witherBlockTags f) x

instance HasWitherableInlineTags (Blocks ann) where
    witherInlineTags f = traverseOf (contents % traversed) (witherInlineTags f)


-- ⭐ Tagged Blocks

data instance Tagged (Blocks ann) =
  TaggedBlocks
    { blocksTag :: Tag ann -- ^ 'ProAbstract.tag'
    , taggedBlocks :: Blocks ann -- ^ 'ProAbstract.content'
    }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable, NFData)

type instance Annotation (Tagged (Blocks ann)) = ann

instance HasTag (Tagged (Blocks ann)) where
    type TagOpticKind (Tagged (Blocks ann)) = A_Lens
    tag = lens blocksTag \x a -> x{ blocksTag = a }

type instance Content (Tagged (Blocks ann)) = Blocks ann

type instance Contents (Tagged (Blocks ann)) = Block ann

instance HasManyAnnotations (Tagged (Blocks ann)) (Tagged (Blocks ann')) where
    allAnnotations = traversalVL \f (TaggedBlocks t b) -> TaggedBlocks
        <$> traverseOf annotation f t <*> traverseOf allAnnotations f b

instance HasAnnotation (Tagged (Blocks ann)) (Tagged (Blocks ann)) where
     annotation = tag % annotation

instance HasContent (Tagged (Blocks ann)) (Tagged (Blocks ann)) where
    content = lens taggedBlocks \x c -> x{ taggedBlocks = c }

instance HasContents (Tagged (Blocks ann)) (Tagged (Blocks ann)) where
    contents = content % contents

instance HasMetadata (Tagged (Blocks ann)) where
    type MetadataOpticKind (Tagged (Blocks ann)) = A_Lens
    metadata = tag % metadata

instance HasManyPlainInlines (Tagged (Blocks ann)) where
    allPlainInlines = content % allPlainInlines

instance HasManyTags (Tagged (Blocks ann)) where
    allTags = tag `adjoin` (content % allTags)
    allInlineTags = allParagraphs % allInlineTags

instance HasManyBlockTags (Tagged (Blocks ann)) where
    allBlockTags = tag `adjoin` (content % allBlockTags)

instance HasWitherableInlineTags (Tagged (Blocks ann)) where
    witherInlineTags f = traverseOf allParagraphs (witherInlineTags f)

instance HasManyMetadata (Tagged (Blocks ann)) where
    allMetadata = allTags % metadata

instance HasManyParagraphs (Tagged (Blocks ann)) where
    allParagraphs = content % allParagraphs

instance HasManyPlainBlocks (Tagged (Blocks ann)) where
    allPlainBlocks = content % allPlainBlocks