~jaro/balkon

28ccd0eea7abd52f74e27f388aae4e0979909ca8 — Jaro 11 months ago 073b66e
Prepare for extending ProtoRun.
M balkon.cabal => balkon.cabal +1 -0
@@ 139,6 139,7 @@ library balkon-internal
        Data.Text.ParagraphLayout.Internal.ParagraphLine,
        Data.Text.ParagraphLayout.Internal.ProtoFragment,
        Data.Text.ParagraphLayout.Internal.ProtoLine,
        Data.Text.ParagraphLayout.Internal.ProtoRun,
        Data.Text.ParagraphLayout.Internal.Script

    build-depends:

A src/Data/Text/ParagraphLayout/Internal/ProtoRun.hs => src/Data/Text/ParagraphLayout/Internal/ProtoRun.hs +15 -0
@@ 0,0 1,15 @@
module Data.Text.ParagraphLayout.Internal.ProtoRun (ProtoRun (..))
where

import Data.Text.Glyphize (Direction)

import Data.Text.ParagraphLayout.Internal.Script
import Data.Text.ParagraphLayout.Internal.Zipper

-- | Intermediate structure for creating
-- `Data.Text.ParagraphLayout.Internal.Run.Run` values.
data ProtoRun = ProtoRun
    { zipper :: Zipper
    , direction :: Maybe Direction
    , script :: ScriptCode
    }

M src/Data/Text/ParagraphLayout/Internal/Run.hs => src/Data/Text/ParagraphLayout/Internal/Run.hs +15 -12
@@ 9,6 9,8 @@ import Data.Text.Foreign (dropWord8, lengthWord8, takeWord8)
import Data.Text.Glyphize (Direction (..))
import qualified Data.Text.ICU.Char as ICUChar

import Data.Text.ParagraphLayout.Internal.ProtoRun (ProtoRun (ProtoRun))
import qualified Data.Text.ParagraphLayout.Internal.ProtoRun as PR
import Data.Text.ParagraphLayout.Internal.ResolvedSpan
import Data.Text.ParagraphLayout.Internal.Script
import Data.Text.ParagraphLayout.Internal.TextContainer


@@ 48,8 50,6 @@ instance SeparableTextContainer Run where
            o' = o + l - l'
    dropWhileEnd p r = r { runText = Text.dropWhileEnd p (runText r) }

type ProtoRun = (Zipper, Maybe Direction, ScriptCode)

-- | Represents a zipper that can advance by at least one character.
data ZipperChoice = ZipperChoice
    { nextChar :: Char


@@ 75,14 75,15 @@ data Merged a = Incompatible | Merged a
spanToRuns :: ResolvedSpan d -> [Run]
spanToRuns s = snd $ mapAccumL run 0 $ protoRuns zipper
    where
        zipper = start $ spanText s
        run acc (z, d, sc) = let t = preceding z in
        wholeText = spanText s
        zipper = start wholeText
        run acc pr = let t = preceding (PR.zipper pr) in
            ( acc + lengthWord8 t
            , Run
                { runOffsetInSpan = acc
                , runText = t
                , runDirection = d
                , runScript = Just sc
                , runDirection = PR.direction pr
                , runScript = Just $ PR.script pr
                }
            )



@@ 93,22 94,24 @@ protoRuns' :: Zipper -> [ProtoRun] -> [ProtoRun]
protoRuns' curZipper curRuns = case considerNext curZipper of
    Nothing -> curRuns
    Just choice ->
        let headRun@(nextZipper, _, _) :| tailRuns = foldRun choice curRuns
        in protoRuns' nextZipper (headRun : tailRuns)
        let headRun :| tailRuns = foldRun choice curRuns
        in protoRuns' (PR.zipper headRun) (headRun : tailRuns)

foldRun :: ZipperChoice -> [ProtoRun] -> NonEmpty ProtoRun

-- If there are no runs, create a new run with a single character.
foldRun x [] = (continuingRun x, d, s) :| []
foldRun x [] = ProtoRun (continuingRun x) d s :| []
    where
        d = charDirection (nextChar x)
        s = charScript (nextChar x)

foldRun x (previousRun@(_, d1, s1) : tailRuns) =
foldRun x (previousRun : tailRuns) =
    case (mergeDirections d1 d2, mergeScripts s1 s2) of
        (Merged d, Merged s) -> (continuingRun x, d, s) :| tailRuns
        _ -> (startingNewRun x, d2, s2) :| previousRun : tailRuns
        (Merged d, Merged s) -> ProtoRun (continuingRun x) d s :| tailRuns
        _ -> ProtoRun (startingNewRun x) d2 s2 :| previousRun : tailRuns
    where
        d1 = PR.direction previousRun
        s1 = PR.script previousRun
        d2 = charDirection (nextChar x)
        s2 = charScript (nextChar x)