From e810016b89d91f9c7418891a188dd1850316d026 Mon Sep 17 00:00:00 2001 From: Jaro Date: Wed, 29 Mar 2023 18:33:08 +0200 Subject: [PATCH] Improve documentation for pagination. --- .../Internal/LinePagination.hs | 48 ++++++++++++------- .../ParagraphLayout/Internal/Paginable.hs | 33 ++++++++----- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs b/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs index fa59a10..d4fd3ce 100644 --- a/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs +++ b/src/Data/Text/ParagraphLayout/Internal/LinePagination.hs @@ -6,15 +6,16 @@ -- to as pages within this module. -- -- Assumptions: +-- -- * Lines are laid out from top to bottom. -- * Each page has the same size. -- (Preceding context may limit the space available on the given page, but it -- is assumed that the space on every following page can be used in full.) module Data.Text.ParagraphLayout.Internal.LinePagination (Line + ,lineHeight ,PageContinuity(Break, Continue) ,bestSplit - ,lineHeight ,paginateLines ) where @@ -38,27 +39,30 @@ class Line a where instance Line Int32 where lineHeight = id --- | Represents the best place, as determined by the `paginateLines` function, --- to place the first line of paginated text. +-- | Represents the best place to place a chunk of paginated content. data PageContinuity = Continue - -- ^ The lines are split so that the prefix can continue on the same page - -- as its preceding context. + -- ^ The content is split so that a given chunk can continue + -- on the same page as its preceding context. -- - -- This may be because all constraints were met, or because adding a page - -- break would have no benefit. + -- This may be because all constraints were met, or because + -- adding a page break would have no benefit. | Break - -- ^ The lines are split so that the prefix should begin on a new page. + -- ^ The content is split so that a given chunk should begin + -- on a new page. -- - -- This may be because the current page does not have enough space - -- to preserve orphan/widow constrains, or because it does not have space - -- for any lines at all. + -- This may be because the current page does not have enough + -- space to preserve orphan/widow constrains, or because it + -- does not have space for any content at all. deriving (Eq, Show, Read, Enum, Bounded) --- | Split a list of lines in order to fit the given pagination constraints. +-- | Split a list of lines in order to meet the given pagination constraints. +-- +-- This is a high-level function that produces the best usable result, +-- even if some constraints have to be violated. -- -- The first component of the output determines whether a page break should -- be inserted before any of the given lines. @@ -129,10 +133,22 @@ split1 :: [a] -> ([a], [a]) split1 xs = (take 1 xs, drop 1 xs) -- | Split a list of lines so that the prefix contains as many lines --- as possible while the total of line heights in the prefix does --- not exceed @h@, the first @o@ lines ("orphans") are kept together, --- and the last @w@ lines ("widows") are kept together. -bestSplit :: Line a => Word -> Word -> Int32 -> [a] -> ([a], [a]) +-- as possible while satisfying the given constraints. +-- +-- This is a low-level function that makes no compromises. +bestSplit :: Line a + => Word + -- ^ Number of lines at the beginning ("orphans") to keep together. + -> Word + -- ^ Number of lines at the end ("widows") to keep together. + -> Int32 + -- ^ Maximum total height of lines in the prefix. + -> [a] + -- ^ Lines to split. + -> ([a], [a]) + -- ^ Two lists of lines that yield the original list when concatenated, + -- where the prefix, if non-empty, matches the given orphan, widow, and + -- maximum height constraints. bestSplit o w h ls = NonEmpty.last $ constrainedSplits o w h ls -- | Split a list of lines in every possible way, from shortest prefix diff --git a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs index bb54e34..9da52fc 100644 --- a/src/Data/Text/ParagraphLayout/Internal/Paginable.hs +++ b/src/Data/Text/ParagraphLayout/Internal/Paginable.hs @@ -35,18 +35,29 @@ data PageOptions = PageOptions } -- | Typeclass for layouts that can be broken into pages. --- --- The first component of the output determines whether a page break should --- be inserted before the paragraph. --- --- The second component of the output contains the portion of the paragraph --- that fits on the page and satisfies the given constraints as much as --- possible. --- --- The third component of the output will be `Just` the remainder of the --- paragraph that can be passed to this function again, or `Nothing` if there --- is nothing left to put on further pages. class Paginable pl where + -- | Break a chunk of content from the given layout, to be placed together + -- on a page. + -- + -- Explanation of return values: + -- + -- * @(`Continue`, p, `Nothing`)@ + -- means that @p@ is the entire layout and fits best on the current page. + -- + -- * @(`Break`, p, `Nothing`)@ + -- means that @p@ is the entire layout and fits best on a new page. + -- In other words, @p@ should be preceded by a page break. + -- + -- * @(`Continue`, p, `Just` rest)@ + -- means that @p@ is a part of the layout that fits best on the current + -- page, and @rest@ should be passed to this function again. + -- In other words, @p@ should be followed by a page break. + -- + -- * @(`Break`, p, `Just` rest)@ + -- means that @p@ is a part of the layout that fits best on a new page, + -- and @rest@ should be passed to this function again. + -- In other words, @p@ should be surrounded by page breaks + -- on both sides. paginate :: PageOptions -> pl -> (PageContinuity, pl, Maybe pl) instance Line a => Paginable [a] where -- 2.30.2