M balkon.cabal => balkon.cabal +1 -0
@@ 126,6 126,7 @@ library balkon-internal
Data.Text.ParagraphLayout.Internal.TextContainer,
Data.Text.ParagraphLayout.Internal.TextOptions,
Data.Text.ParagraphLayout.Internal.Tree,
+ Data.Text.ParagraphLayout.Internal.TreeOfTexts,
Data.Text.ParagraphLayout.Internal.Zipper
-- Modules used purely internally and not in any tests.
M src/Data/Text/ParagraphLayout/Internal/Rich/Paragraph.hs => src/Data/Text/ParagraphLayout/Internal/Rich/Paragraph.hs +10 -0
@@ 1,5 1,6 @@
module Data.Text.ParagraphLayout.Internal.Rich.Paragraph
( Paragraph (..)
+ , constructParagraph
, paragraphSpanBounds
, paragraphSpanTexts
, paragraphText
@@ 11,6 12,7 @@ import qualified Data.List.NonEmpty as NonEmpty
import Data.Text.Array (Array)
import Data.Text.Internal (Text (Text))
+import qualified Data.Text.ParagraphLayout.Internal.TreeOfTexts as Texts
import Data.Text.ParagraphLayout.Internal.ParagraphOptions
import Data.Text.ParagraphLayout.Internal.Tree
@@ 48,6 50,14 @@ data Paragraph d = Paragraph
ParagraphOptions
-- ^ Options applying to the paragraph as a whole.
+constructParagraph :: Text -> Texts.RootNode d -> Text -> ParagraphOptions ->
+ Paragraph d
+constructParagraph prefix root suffix = Paragraph arr afterPrefix root'
+ where
+ (Text arr beforePrefix _) = txt
+ afterPrefix = beforePrefix + prefixLen
+ (txt, prefixLen, root') = Texts.toStrict prefix root suffix
+
-- | Calculate the offsets into the `Paragraph`'s underlying `Data.Text.Array`
-- where each text node starts and ends, in ascending order. The resulting list
-- will be one larger than the number of text nodes in the input.
A src/Data/Text/ParagraphLayout/Internal/TreeOfTexts.hs => src/Data/Text/ParagraphLayout/Internal/TreeOfTexts.hs +88 -0
@@ 0,0 1,88 @@
+-- | Represents the contents of a paragraph as a tree of boxes and texts.
+--
+-- This is intended for easier construction of paragraphs, at the cost of lower
+-- performance. All texts will be concatenated together by layout functions.
+module Data.Text.ParagraphLayout.Internal.TreeOfTexts
+ ( RootNode (..)
+ , InnerNode (..)
+ , Box (..)
+ , toStrict
+ )
+where
+
+import Data.Text (Text)
+import Data.Text.Foreign (lengthWord8)
+import qualified Data.Text.Lazy as Lazy (toStrict)
+import qualified Data.Text.Internal.Lazy as Lazy (Text, chunk, empty)
+
+import Data.Text.ParagraphLayout.Internal.BoxOptions
+import Data.Text.ParagraphLayout.Internal.TextOptions
+import qualified Data.Text.ParagraphLayout.Internal.Tree as Strict
+
+-- | Root of the paragraph tree.
+data RootNode d
+
+ = RootBox (Box d)
+ -- ^ The root 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.
+ Text
+ -- ^ Text contents of the node.
+
+-- | 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.
+
+toStrict :: Text -> RootNode d -> Text -> (Text, Int, Strict.RootNode d)
+toStrict prefix root suffix = (txt, initialOffset, root')
+ where
+ txt = Lazy.toStrict $ Lazy.chunk prefix txtTail
+ initialOffset = lengthWord8 prefix
+ (txtTail, root') = strictRoot (Lazy.chunk suffix Lazy.empty) root
+
+strictRoot :: Lazy.Text -> RootNode d -> (Lazy.Text, Strict.RootNode d)
+strictRoot t (RootBox b) = (t', Strict.RootBox b')
+ where
+ (t', b') = strictBox t b
+
+strictBox :: Lazy.Text -> Box d -> (Lazy.Text, Strict.Box d)
+strictBox t (Box nodes opts) = (t', Strict.Box nodes' opts)
+ where
+ (t', nodes') = strictNodes t nodes
+
+strictNodes :: Lazy.Text -> [InnerNode d] -> (Lazy.Text, [Strict.InnerNode d])
+strictNodes t [] = (t, [])
+strictNodes t (node : nodes) = (t'', node' : nodes')
+ where
+ (t'', node') = strictNode t' node
+ (t', nodes') = strictNodes t nodes
+
+strictNode :: Lazy.Text -> InnerNode d -> (Lazy.Text, Strict.InnerNode d)
+strictNode suffix (TextSequence d txt) = (combinedText, node)
+ where
+ combinedText = Lazy.chunk txt suffix
+ node = Strict.TextSequence d (lengthWord8 txt)
+strictNode suffix (InlineBox d b o) = (combinedText, Strict.InlineBox d node o)
+ where
+ (combinedText, node) = strictBox suffix b