M balkon.cabal => balkon.cabal +1 -0
@@ 119,6 119,7 @@ library balkon-internal
Data.Text.ParagraphLayout.Internal.Span,
Data.Text.ParagraphLayout.Internal.TextContainer,
Data.Text.ParagraphLayout.Internal.TextOptions,
+ Data.Text.ParagraphLayout.Internal.Tree,
Data.Text.ParagraphLayout.Internal.Zipper
-- Modules used purely internally and not in any tests.
A src/Data/Text/ParagraphLayout/Internal/Tree.hs => src/Data/Text/ParagraphLayout/Internal/Tree.hs +88 -0
@@ 0,0 1,88 @@
+-- | Represents the contents of a paragraph as a tree.
+--
+-- The tree is a hierarchy of boxes, with one box always present as the root.
+-- Each box may contain any combination of text sequences and other boxes.
+module Data.Text.ParagraphLayout.Internal.Tree
+ ( RootNode (..)
+ , InnerNode (..)
+ , Box (..)
+ , Leaf (..)
+ , flatten
+ )
+where
+
+import Data.Text.ParagraphLayout.Internal.BoxOptions
+import Data.Text.ParagraphLayout.Internal.TextOptions
+
+-- | Root of the paragraph tree.
+data RootNode d
+
+ = RootBox
+ -- ^ The root inline box. Always present in a paragraph.
+ --
+ -- Cannot be styled directly, but can still set options for formatting
+ -- text sequences directly descending from this box.
+ (Box d)
+ -- ^ Contents of the box.
+
+-- | Non-root node of the paragraph tree.
+data InnerNode d
+
+ = InlineBox
+ -- ^ An inline box, nested in another box.
+ d
+ -- ^ User-defined data associated with the box.
+ (Box d)
+ -- ^ Contents of the box.
+ BoxOptions
+ -- ^ Style options to apply to the inline box.
+
+ | TextSequence
+ -- ^ A leaf node containing text.
+ d
+ -- ^ User-defined data associated with the text node.
+ Int
+ -- ^ Byte offset to the next text node or the end of the paragraph text.
+
+-- | A box with content and a defined format. Corresponds to a DOM element.
+data Box d = Box
+
+ [InnerNode d]
+ -- ^ Text nodes and other boxes contained by this box.
+
+ TextOptions
+ -- ^ Style options to apply to text sequences directly contained
+ -- by this box.
+
+-- TODO: we need a way to test box equality, maybe add indexes?
+type BoxPath d = [(d, BoxOptions)]
+
+-- | Representation of a leaf node of the tree after flattening.
+data Leaf d = TextLeaf
+
+ d
+ -- ^ User-defined data associated with the text node.
+
+ Int
+ -- ^ Byte offset to the next text node or the end of the paragraph text.
+
+ TextOptions
+ -- ^ Style options to apply to this text sequence.
+
+ (BoxPath d)
+ -- ^ Inline boxes found on the path from this text sequence to the root
+ -- of the original tree.
+
+-- | Convert the tree to a flat list of its leaf nodes (text sequences).
+flatten :: RootNode d -> [Leaf d]
+flatten (RootBox (Box ns textOpts)) = flattenNodes [] textOpts ns
+
+flattenNodes :: BoxPath d -> TextOptions -> [InnerNode d] -> [Leaf d]
+flattenNodes _ _ [] = []
+flattenNodes path textOpts (n : ns) =
+ flattenNode path textOpts n ++ flattenNodes path textOpts ns
+
+flattenNode :: BoxPath d -> TextOptions -> InnerNode d -> [Leaf d]
+flattenNode path textOpts (TextSequence d len) = [TextLeaf d len textOpts path]
+flattenNode path _ (InlineBox d (Box ns textOpts) boxOpts) =
+ flattenNodes ((d, boxOpts) : path) textOpts ns