@@ 2,6 2,8 @@ module Data.Text.ParagraphLayout.Internal.Paragraph
( Paragraph (..)
, ParagraphOptions (..)
, paragraphSpanBounds
+ , paragraphSpanTexts
+ , paragraphText
)
where
@@ 10,6 12,7 @@ import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NonEmpty
import Data.Text.Array (Array)
import Data.Text.Glyphize (Font)
+import Data.Text.Internal (Text (Text))
import Data.Text.ParagraphLayout.Internal.LineHeight
import Data.Text.ParagraphLayout.Internal.Span
@@ 79,4 82,22 @@ data ParagraphOptions = ParagraphOptions
-- will be one larger than the list of input spans.
paragraphSpanBounds :: Paragraph -> NonEmpty Int
paragraphSpanBounds (Paragraph _ initialOffset spans _) =
+ -- TODO: Consider adding checks for array bounds.
NonEmpty.scanl (+) initialOffset (map spanLength spans)
+
+-- | Turn each span of the input `Paragraph` into a `Text`.
+paragraphSpanTexts :: Paragraph -> [Text]
+paragraphSpanTexts p@(Paragraph arr _ _ _) = zipWith toText sStarts sEnds
+ where
+ toText start end = Text arr start (end - start)
+ sStarts = NonEmpty.init sBounds
+ sEnds = NonEmpty.tail sBounds
+ sBounds = paragraphSpanBounds p
+
+-- | Turn all spans of the input `Paragraph` into one combined `Text`.
+paragraphText :: Paragraph -> Text
+paragraphText p@(Paragraph arr _ _ _) = Text arr start (end - start)
+ where
+ start = NonEmpty.head sBounds
+ end = NonEmpty.last sBounds
+ sBounds = paragraphSpanBounds p
@@ 8,6 8,7 @@ import Data.List (mapAccumL)
import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, (<|))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Maybe (catMaybes)
+import Data.Text (Text)
import Data.Text.Foreign (lengthWord8)
import Data.Text.Glyphize
( Buffer (..)
@@ 21,7 22,6 @@ import Data.Text.Glyphize
)
import Data.Text.ICU (Breaker, LocaleName, breakCharacter, breakLine)
import qualified Data.Text.ICU as BreakStatus (Line (Hard))
-import Data.Text.Internal (Text (Text))
import qualified Data.Text.Lazy as Lazy
import Data.Text.ParagraphLayout.Internal.BiDiReorder
@@ 259,25 259,24 @@ shapeRun (WithSpan rs run) = shape font buffer features
features = []
resolveSpans :: Paragraph -> [RS.ResolvedSpan]
-resolveSpans p@(Paragraph arr pStart spans pOpts) = do
+resolveSpans p@(Paragraph _ pStart spans pOpts) = do
let sBounds = paragraphSpanBounds p
- let pEnd = NonEmpty.last sBounds
+ let sTexts = paragraphSpanTexts p
+ let pText = paragraphText p
let sStarts = NonEmpty.init sBounds
- let sLengths = map spanLength spans
- (i, s, sStart, sLen) <- getZipList $ (,,,)
+ (i, s, sStart, sText) <- getZipList $ (,,,)
<$> ZipList [0 ..]
<*> ZipList spans
<*> ZipList sStarts
- <*> ZipList sLengths
+ <*> ZipList sTexts
let lang = spanLanguage $ spanOptions s
- let lBreaks = paragraphBreaks breakLine p pEnd lang
- let cBreaks = paragraphBreaks breakCharacter p pEnd lang
+ let lBreaks = paragraphBreaks breakLine pText lang
+ let cBreaks = paragraphBreaks breakCharacter pText lang
return RS.ResolvedSpan
{ RS.spanIndex = i
, RS.spanOffsetInParagraph = sStart - pStart
- -- TODO: Consider adding checks for array bounds.
- , RS.spanText = Text arr sStart sLen
+ , RS.spanText = sText
, RS.spanFont = paragraphFont pOpts
, RS.spanLineHeight = paragraphLineHeight pOpts
, RS.spanLanguage = lang
@@ 285,12 284,9 @@ resolveSpans p@(Paragraph arr pStart spans pOpts) = do
, RS.spanCharacterBreaks = subOffsetsDesc (sStart - pStart) cBreaks
}
-paragraphBreaks :: (LocaleName -> Breaker a) -> Paragraph -> Int -> String ->
- [(Int, a)]
-paragraphBreaks breakFunc (Paragraph arr off _ _) end lang =
- breaksDesc (breakFunc (locale lang LBAuto)) paragraphText
- where
- paragraphText = Text arr off (end - off)
+paragraphBreaks :: (LocaleName -> Breaker a) -> Text -> String -> [(Int, a)]
+paragraphBreaks breakFunc txt lang =
+ breaksDesc (breakFunc (locale lang LBAuto)) txt
runLineBreaks :: WithSpan Run -> [(Int, BreakStatus.Line)]
runLineBreaks (WithSpan rs run) =