From 0975c99f8e8fc2f33c968daa8968444bb0c026c5 Mon Sep 17 00:00:00 2001 From: Jaro Date: Fri, 16 Jun 2023 20:42:39 +0200 Subject: [PATCH] Refactor lineNumbers into a common module. --- balkon.cabal | 1 + .../ParagraphLayout/Internal/LineNumbers.hs | 23 +++++++++++++++++++ .../ParagraphLayout/Internal/Paginable.hs | 3 ++- .../ParagraphLayout/Internal/ParagraphLine.hs | 16 ++----------- .../Internal/Plain/ParagraphLayout.hs | 4 ++++ .../Internal/Rich/ParagraphLayout.hs | 4 ++++ 6 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 src/Data/Text/ParagraphLayout/Internal/LineNumbers.hs diff --git a/balkon.cabal b/balkon.cabal index 375ea59..77b9c07 100644 --- a/balkon.cabal +++ b/balkon.cabal @@ -137,6 +137,7 @@ library balkon-internal -- Modules used purely internally and not in any tests. other-modules: Data.Text.ParagraphLayout.Internal.Layout, + Data.Text.ParagraphLayout.Internal.LineNumbers, Data.Text.ParagraphLayout.Internal.ParagraphExtents, Data.Text.ParagraphLayout.Internal.ParagraphLine, Data.Text.ParagraphLayout.Internal.ProtoFragment, diff --git a/src/Data/Text/ParagraphLayout/Internal/LineNumbers.hs b/src/Data/Text/ParagraphLayout/Internal/LineNumbers.hs new file mode 100644 index 0000000..e0f2750 --- /dev/null +++ b/src/Data/Text/ParagraphLayout/Internal/LineNumbers.hs @@ -0,0 +1,23 @@ +module Data.Text.ParagraphLayout.Internal.LineNumbers + ( LineNumbers + , lineNumbers + , lineNumbersWithDuplication + ) +where + +import qualified Data.List.NonEmpty as NonEmpty + +-- | Data types that contain numbered lines. +class LineNumbers ml where + + -- | A list of all line numbers in ascending order, + -- with possible duplicates. + lineNumbersWithDuplication :: ml -> [Int] + +-- | A list of all unique line numbers, in ascending order. +lineNumbers :: (LineNumbers ml) => ml -> [Int] +lineNumbers ml = dedupe $ lineNumbersWithDuplication ml + +-- | Remove duplicates from a sorted list. +dedupe :: Eq a => [a] -> [a] +dedupe xs = map NonEmpty.head $ NonEmpty.group xs diff --git a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs index 312782b..1b805b8 100644 --- a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs +++ b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs @@ -8,6 +8,7 @@ where import Data.Int (Int32) +import Data.Text.ParagraphLayout.Internal.LineNumbers import Data.Text.ParagraphLayout.Internal.LinePagination import Data.Text.ParagraphLayout.Internal.ParagraphLine import qualified Data.Text.ParagraphLayout.Internal.Plain.ParagraphLayout @@ -86,7 +87,7 @@ instance Paginable (Plain.ParagraphLayout d) where instance Paginable (Rich.ParagraphLayout d) where paginate = paginateLayout -paginateLayout :: (Line a, GenericLayout a) => +paginateLayout :: (Line a, LineNumbers a, GenericLayout a) => PageOptions -> a -> (PageContinuity, a, Maybe a) paginateLayout opts pl = case paginate opts (cutLines pl) of diff --git a/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs b/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs index 4c0aff8..4966eae 100644 --- a/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs +++ b/src/Data/Text/ParagraphLayout/Internal/ParagraphLine.hs @@ -7,9 +7,9 @@ module Data.Text.ParagraphLayout.Internal.ParagraphLine where import Data.Int (Int32) -import qualified Data.List.NonEmpty as NonEmpty import Data.Text.ParagraphLayout.Internal.Fragment +import Data.Text.ParagraphLayout.Internal.LineNumbers import qualified Data.Text.ParagraphLayout.Internal.Plain.ParagraphLayout as P import qualified Data.Text.ParagraphLayout.Internal.Rich.ParagraphLayout as R import Data.Text.ParagraphLayout.Internal.Rect @@ -25,9 +25,6 @@ class GenericLayout pl where -- | Actual distance between the paragraph origin and the nearest fragment. topDistance :: pl -> Int32 - -- | A list of all unique line numbers that have laid out content. - lineNumbers :: pl -> [Int] - -- | Keep only fragments with the given line number. limitFragments :: Int -> pl -> pl @@ -42,7 +39,6 @@ instance GenericLayout (P.ParagraphLayout d) where empty = P.emptyParagraphLayout rect = P.paragraphRect topDistance pl = topFragmentOrigin $ P.paragraphFragments pl - lineNumbers pl = uniqueFragmentLines $ P.paragraphFragments pl limitFragments n = P.filterFragments (fragmentIsOnLine n) shiftFragments dy = P.mapFragments (shiftFragment dy) appendFragments = P.appendFragments @@ -51,13 +47,12 @@ instance GenericLayout (R.ParagraphLayout d) where empty = R.emptyParagraphLayout rect = R.paragraphRect topDistance pl = topFragmentOrigin $ R.paragraphFragments pl - lineNumbers pl = uniqueFragmentLines $ R.paragraphFragments pl limitFragments n = R.filterFragments (fragmentIsOnLine n) shiftFragments dy = R.mapFragments (shiftFragment dy) appendFragments = R.appendFragments -- | Split the given paragraph layout into single-line layouts. -cutLines :: GenericLayout pl => pl -> [pl] +cutLines :: (GenericLayout pl, LineNumbers pl) => pl -> [pl] cutLines pl = map (\ n -> cutLine n pl) (lineNumbers pl) -- | Reduce the given paragraph layout to fragments with the given line number. @@ -71,13 +66,6 @@ trimTop pl = shiftFragments (-topDistance pl) pl topFragmentOrigin :: [Fragment d] -> Int32 topFragmentOrigin frags = maximum $ map (y_origin . fragmentRect) frags -uniqueFragmentLines :: [Fragment d] -> [Int] -uniqueFragmentLines frags = dedupe $ map fragmentLine frags - --- | Remove duplicates from a sorted list. -dedupe :: Eq a => [a] -> [a] -dedupe xs = map NonEmpty.head $ NonEmpty.group xs - -- | Put the given paragraph layouts together as a vertically contiguous -- sequence. mergeLines :: GenericLayout pl => [pl] -> pl diff --git a/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs b/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs index 5f18917..ddad8ac 100644 --- a/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs +++ b/src/Data/Text/ParagraphLayout/Internal/Plain/ParagraphLayout.hs @@ -13,6 +13,7 @@ where import Data.Int (Int32) import Data.Text.ParagraphLayout.Internal.Fragment +import Data.Text.ParagraphLayout.Internal.LineNumbers import Data.Text.ParagraphLayout.Internal.LinePagination import Data.Text.ParagraphLayout.Internal.ParagraphExtents import Data.Text.ParagraphLayout.Internal.Rect @@ -26,6 +27,9 @@ data ParagraphLayout d = ParagraphLayout } deriving (Eq, Read, Show) +instance LineNumbers (ParagraphLayout d) where + lineNumbersWithDuplication pl = map fragmentLine $ paragraphFragments pl + instance Line (ParagraphLayout d) where lineHeight pl = height $ paragraphRect pl diff --git a/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs b/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs index 50e4c99..719a6de 100644 --- a/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs +++ b/src/Data/Text/ParagraphLayout/Internal/Rich/ParagraphLayout.hs @@ -14,6 +14,7 @@ where import Data.Int (Int32) import Data.Text.ParagraphLayout.Internal.Fragment +import Data.Text.ParagraphLayout.Internal.LineNumbers import Data.Text.ParagraphLayout.Internal.LinePagination import Data.Text.ParagraphLayout.Internal.ParagraphExtents import Data.Text.ParagraphLayout.Internal.Rect @@ -29,6 +30,9 @@ data ParagraphLayout d = ParagraphLayout } deriving (Eq, Read, Show) +instance LineNumbers (ParagraphLayout d) where + lineNumbersWithDuplication pl = map fragmentLine $ paragraphFragments pl + instance Line (ParagraphLayout d) where lineHeight pl = height $ paragraphRect pl -- 2.30.2