Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ghc-doclayout for openSUSE:Factory checked in at 2026-06-10 15:59:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-doclayout (Old) and /work/SRC/openSUSE:Factory/.ghc-doclayout.new.2375 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-doclayout" Wed Jun 10 15:59:32 2026 rev:13 rq:1358361 version:0.5.0.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-doclayout/ghc-doclayout.changes 2025-09-11 14:43:29.262319292 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-doclayout.new.2375/ghc-doclayout.changes 2026-06-10 16:00:39.999399357 +0200 @@ -1,0 +2,50 @@ +Wed Jun 3 07:15:04 UTC 2026 - Peter Simons <[email protected]> + +- Update doclayout to version 0.5.0.3. + ## 0.5.0.3 + + * Tests: Go back to using withMaxSuccess for compatibility with older + QuickCheck versions. + + ## 0.5.0.2 + + * Performance optimizations: + + + Fuse double modify calls in outp, newline, and FCookedText handler. + + + Cache polymorphic prefix in RenderState. Add prefixA, prefixTrimmedA, + and prefixLen fields to RenderState that cache the polymorphic + conversions of the Text prefix. This eliminates + the per-line fromString/T.unpack/realLength conversions in outp, + newline, and the FCookedText handler. Add a setPrefix helper that + updates all cached fields atomically. The block handler computes the + space-appended prefix incrementally to avoid expensive recomputation + on deeply nested blocks. + + + Avoid redundant realLength calls in mergeBlocks padding. + Thread precomputed line widths through the merge process by changing + the internal representation from (Int, [a]) to (Int, [(Int, a)]) where + the inner Int is each line's rendered width. This avoids calling + realLength on every line during every merge pass; widths are computed + once in toBlockSpec and carried through. + + + Remove redundant normalize in flatten for Prefixed. renderList + already normalizes when processing FPrefixed. This removes the + double traversal. + + + Use strict foldl' in Attributed foldlChar instance. + + + Add shortcuts for Thai, emoji modifiers, CJK, and fullwidth chars. + Add new shortcuts to updateMatchStateNarrow and updateMatchStateWide: + + - Thai script (U+0E00-U+0E7F) with combining marks for vowels/tones + - Zero-width joiner (U+200D) with inline emoji-joining logic + - Emoji presentation variation selector (U+FE0F) + - Emoji skin tone modifiers (U+1F3FB-U+1F3FF) + - CJK Compatibility Ideographs (U+F900-U+FAFF) + - Fullwidth forms (U+FF01-U+FF60, U+FFE0-U+FFE6) + - Supplementary CJK Extension B+ (U+20000-U+3FFFF) + + * Use withNumTests instead of deprecated withMaxSuccess in test suite. + +------------------------------------------------------------------- Old: ---- doclayout-0.5.0.1.tar.gz New: ---- doclayout-0.5.0.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-doclayout.spec ++++++ --- /var/tmp/diff_new_pack.qGILHe/_old 2026-06-10 16:00:41.327454392 +0200 +++ /var/tmp/diff_new_pack.qGILHe/_new 2026-06-10 16:00:41.331454559 +0200 @@ -1,7 +1,7 @@ # # spec file for package ghc-doclayout # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,7 +20,7 @@ %global pkgver %{pkg_name}-%{version} %bcond_with tests Name: ghc-%{pkg_name} -Version: 0.5.0.1 +Version: 0.5.0.3 Release: 0 Summary: A prettyprinting library for laying out text documents License: BSD-3-Clause ++++++ doclayout-0.5.0.1.tar.gz -> doclayout-0.5.0.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/doclayout-0.5.0.1/changelog.md new/doclayout-0.5.0.3/changelog.md --- old/doclayout-0.5.0.1/changelog.md 2001-09-09 03:46:40.000000000 +0200 +++ new/doclayout-0.5.0.3/changelog.md 2001-09-09 03:46:40.000000000 +0200 @@ -1,5 +1,51 @@ # doclayout +## 0.5.0.3 + + * Tests: Go back to using withMaxSuccess for compatibility with older + QuickCheck versions. + +## 0.5.0.2 + + * Performance optimizations: + + + Fuse double modify calls in outp, newline, and FCookedText handler. + + + Cache polymorphic prefix in RenderState. Add prefixA, prefixTrimmedA, + and prefixLen fields to RenderState that cache the polymorphic + conversions of the Text prefix. This eliminates + the per-line fromString/T.unpack/realLength conversions in outp, + newline, and the FCookedText handler. Add a setPrefix helper that + updates all cached fields atomically. The block handler computes the + space-appended prefix incrementally to avoid expensive recomputation + on deeply nested blocks. + + + Avoid redundant realLength calls in mergeBlocks padding. + Thread precomputed line widths through the merge process by changing + the internal representation from (Int, [a]) to (Int, [(Int, a)]) where + the inner Int is each line's rendered width. This avoids calling + realLength on every line during every merge pass; widths are computed + once in toBlockSpec and carried through. + + + Remove redundant normalize in flatten for Prefixed. renderList + already normalizes when processing FPrefixed. This removes the + double traversal. + + + Use strict foldl' in Attributed foldlChar instance. + + + Add shortcuts for Thai, emoji modifiers, CJK, and fullwidth chars. + Add new shortcuts to updateMatchStateNarrow and updateMatchStateWide: + + - Thai script (U+0E00-U+0E7F) with combining marks for vowels/tones + - Zero-width joiner (U+200D) with inline emoji-joining logic + - Emoji presentation variation selector (U+FE0F) + - Emoji skin tone modifiers (U+1F3FB-U+1F3FF) + - CJK Compatibility Ideographs (U+F900-U+FAFF) + - Fullwidth forms (U+FF01-U+FF60, U+FFE0-U+FFE6) + - Supplementary CJK Extension B+ (U+20000-U+3FFFF) + + * Use withNumTests instead of deprecated withMaxSuccess in test suite. + ## 0.5.0.1 * Have `nestle` remove leading CarriageReturn. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/doclayout-0.5.0.1/doclayout.cabal new/doclayout-0.5.0.3/doclayout.cabal --- old/doclayout-0.5.0.1/doclayout.cabal 2001-09-09 03:46:40.000000000 +0200 +++ new/doclayout-0.5.0.3/doclayout.cabal 2001-09-09 03:46:40.000000000 +0200 @@ -1,5 +1,5 @@ name: doclayout -version: 0.5.0.1 +version: 0.5.0.3 synopsis: A prettyprinting library for laying out text documents. description: doclayout is a prettyprinting library for laying out text documents, with several features not present @@ -33,8 +33,6 @@ emojis >=0.1.2, mtl, safe - if !impl(ghc >= 8.0) - build-depends: semigroups == 0.18.* default-language: Haskell2010 ghc-options: -Wall -fno-warn-unused-do-bind diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/doclayout-0.5.0.1/src/Text/DocLayout/HasChars.hs new/doclayout-0.5.0.3/src/Text/DocLayout/HasChars.hs --- old/doclayout-0.5.0.1/src/Text/DocLayout/HasChars.hs 2001-09-09 03:46:40.000000000 +0200 +++ new/doclayout-0.5.0.3/src/Text/DocLayout/HasChars.hs 2001-09-09 03:46:40.000000000 +0200 @@ -9,6 +9,7 @@ import qualified Data.Text.Lazy as TL import Data.Text (Text) import qualified Data.Text.Lazy.Builder as B +import qualified Data.Foldable as F import Data.List (foldl', uncons) import Data.Maybe (fromMaybe) import Text.DocLayout.Attributed @@ -74,8 +75,7 @@ foldlChar _ acc (Attributed S.Empty) = acc foldlChar f acc (Attributed ((Attr _ _ x) :<| xs)) = let l = foldlChar f acc x - innerFold e a = foldlChar f a e - in foldr innerFold l xs + in F.foldl' (\a (Attr _ _ e) -> foldlChar f a e) l xs splitLines (Attributed s) = fmap Attributed $ reverse $ go ([], S.empty) s where go (lns, cur) S.Empty = cur : lns diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/doclayout-0.5.0.1/src/Text/DocLayout.hs new/doclayout-0.5.0.3/src/Text/DocLayout.hs --- old/doclayout-0.5.0.1/src/Text/DocLayout.hs 2001-09-09 03:46:40.000000000 +0200 +++ new/doclayout-0.5.0.3/src/Text/DocLayout.hs 2001-09-09 03:46:40.000000000 +0200 @@ -298,7 +298,7 @@ flatten (CookedText n a) = [FCookedText n a] flatten (Prefixed p d) | null f = [] | otherwise = [FPrefixed p (N.fromList f)] - where f = (normalize . flatten) d + where f = flatten d flatten (BeforeNonBlank d) | null f = [] | otherwise = [FBeforeNonBlank (N.fromList f)] where f = flatten d @@ -320,14 +320,26 @@ type DocState a = State (RenderState a) () data RenderState a = RenderState{ - output :: [Attr a] -- ^ In reverse order - , prefix :: Text - , usePrefix :: Bool - , lineLength :: Maybe Int -- ^ 'Nothing' means no wrapping - , column :: Int - , newlines :: Int -- ^ Number of preceding newlines - , fontStack :: [Font] - , linkTarget :: Maybe Text -- ^ Current link target + output :: [Attr a] -- ^ In reverse order + , prefix :: Text + , prefixA :: a -- cached: fromString (T.unpack prefix) + , prefixTrimmedA :: a -- cached: fromString (T.unpack (T.dropWhileEnd isSpace prefix)) + , prefixLen :: !Int -- cached: realLength prefix + , usePrefix :: Bool + , lineLength :: Maybe Int -- ^ 'Nothing' means no wrapping + , column :: Int + , newlines :: Int -- ^ Number of preceding newlines + , fontStack :: [Font] + , linkTarget :: Maybe Text -- ^ Current link target + } + +setPrefix :: HasChars a => Text -> RenderState a -> RenderState a +setPrefix p st = + let pa = fromString $ T.unpack p + in st{ prefix = p + , prefixA = pa + , prefixTrimmedA = fromString $ T.unpack $ T.dropWhileEnd isSpace p + , prefixLen = realLength pa } peekFont :: RenderState a -> Font @@ -338,27 +350,30 @@ newline :: HasChars a => DocState a newline = do st' <- get - let rawpref = prefix st' - when (column st' == 0 && usePrefix st' && not (T.null rawpref)) $ do - let pref = fromString $ T.unpack $ T.dropWhileEnd isSpace rawpref - modify $ \st -> st{ output = Attr Nothing baseFont pref : output st - , column = column st + realLength pref } - modify $ \st -> st { output = Attr Nothing baseFont "\n" : output st - , column = 0 - , newlines = newlines st + 1 - } + let nl = Attr Nothing baseFont "\n" + put $! if column st' == 0 && usePrefix st' && not (T.null (prefix st')) + then let pref = prefixTrimmedA st' + in st'{ output = nl : Attr Nothing baseFont pref : output st' + , column = 0 + , newlines = newlines st' + 1 } + else st'{ output = nl : output st' + , column = 0 + , newlines = newlines st' + 1 } outp :: HasChars a => Int -> a -> DocState a outp off s = do -- offset >= 0 (0 might be combining char) st' <- get - let pref = if usePrefix st' then fromString $ T.unpack $ prefix st' else mempty - let font = peekFont st' - when (column st' == 0 && not (isNull pref && font == baseFont)) $ - modify $ \st -> st{ output = Attr Nothing baseFont pref : output st - , column = column st + realLength pref } - modify $ \st -> st{ output = Attr (linkTarget st) font s : output st - , column = column st + off - , newlines = 0 } + let pref = if usePrefix st' then prefixA st' else mempty + font = peekFont st' + put $! if column st' == 0 && not (isNull pref && font == baseFont) + then st'{ output = Attr (linkTarget st') font s + : Attr Nothing baseFont pref + : output st' + , column = prefixLen st' + off + , newlines = 0 } + else st'{ output = Attr (linkTarget st') font s : output st' + , column = column st' + off + , newlines = 0 } -- | Synonym for 'renderPlain'. render :: HasChars a => Maybe Int -> Doc a -> a @@ -397,6 +412,9 @@ where startingState = RenderState{ output = mempty , prefix = mempty + , prefixA = mempty + , prefixTrimmedA = mempty + , prefixLen = 0 , usePrefix = True , lineLength = linelen , column = 0 @@ -434,20 +452,21 @@ normalize (FBreakingSpace : FBreakingSpace : xs) = normalize (FBreakingSpace:xs) normalize (x:xs) = x : normalize xs -mergeBlocks :: HasChars a => Int -> (Int, [a]) -> (Int, [a]) -> (Int, [a]) +mergeBlocks :: HasChars a => Int -> (Int, [(Int, a)]) -> (Int, [(Int, a)]) -> (Int, [(Int, a)]) mergeBlocks h (w1,lns1) (w2,lns2) = - (w, zipWith (\l1 l2 -> pad w1 l1 <> l2) lns1' lns2') + (w, zipWith merge lns1' lns2') where w = w1 + w2 len1 = length $ take h lns1 -- note lns1 might be infinite len2 = length $ take h lns2 lns1' = if len1 < h - then lns1 ++ replicate (h - len1) mempty + then lns1 ++ replicate (h - len1) (0, mempty) else take h lns1 lns2' = if len2 < h - then lns2 ++ replicate (h - len2) mempty + then lns2 ++ replicate (h - len2) (0, mempty) else take h lns2 - pad n s = s <> replicateChar (n - realLength s) ' ' + merge (len1a, l1) (len2a, l2) = (w1 + len2a, pad w1 len1a l1 <> l2) + pad n len s = s <> replicateChar (n - len) ' ' renderList :: HasChars a => [FlatDoc a] -> DocState a renderList [] = return () @@ -458,14 +477,15 @@ renderList (FCookedText off s : xs) = do st' <- get - let pref = if usePrefix st' then fromString $ T.unpack $ prefix st' else mempty - let elems (Attributed x) = reverse $ toList x - when (column st' == 0 && not (isNull pref)) $ - modify $ \st -> st{ output = Attr Nothing baseFont pref : output st - , column = column st + realLength pref } - modify $ \st -> st{ output = elems s ++ output st - , column = column st + off - , newlines = 0 } + let pref = if usePrefix st' then prefixA st' else mempty + elems (Attributed x) = reverse $ toList x + put $! if column st' == 0 && not (isNull pref) + then st'{ output = elems s ++ (Attr Nothing baseFont pref : output st') + , column = prefixLen st' + off + , newlines = 0 } + else st'{ output = elems s ++ output st' + , column = column st' + off + , newlines = 0 } renderList xs -- FStyleOpen and FStyleClose are balanced by construction when we create @@ -507,10 +527,15 @@ renderList (FPrefixed pref d : xs) = do st <- get let oldPref = prefix st - put st{ prefix = prefix st <> pref } + oldPrefixA = prefixA st + oldPrefixTrimmedA = prefixTrimmedA st + oldPrefixLen = prefixLen st + put $! setPrefix (prefix st <> pref) st renderList $ normalize $ N.toList d - modify $ \s -> s{ prefix = oldPref } - -- renderDoc CarriageReturn + modify $ \s -> s{ prefix = oldPref + , prefixA = oldPrefixA + , prefixTrimmedA = oldPrefixTrimmedA + , prefixLen = oldPrefixLen } renderList xs renderList (FFlush d : xs) = do @@ -574,17 +599,28 @@ let heightOf (FBlock _ ls) = length ls heightOf _ = 1 let maxheight = maximum $ map heightOf (b:bs) - let toBlockSpec (FBlock w ls) = (w, ls) - toBlockSpec (FVFill w t) = (w, map (singleton . (Attr (linkTarget st) font)) (take maxheight $ repeat t)) + let toBlockSpec (FBlock w ls) = (w, map (\l -> (realLength l, l)) ls) + toBlockSpec (FVFill w t) = (w, map (\l -> (realLength l, l)) $ + map (singleton . (Attr (linkTarget st) font)) (take maxheight $ repeat t)) toBlockSpec _ = (0, []) let (_, lns') = foldl (mergeBlocks maxheight) (toBlockSpec b) (map toBlockSpec bs) let oldPref = prefix st - case column st - realLength oldPref of - n | n > 0 -> modify $ \s -> s{ prefix = oldPref <> T.replicate n " " } + oldPrefixA = prefixA st + oldPrefixTrimmedA = prefixTrimmedA st + oldPrefixLen = prefixLen st + case column st - oldPrefixLen of + n | n > 0 -> modify $ \s -> + s{ prefix = oldPref <> T.replicate n " " + , prefixA = prefixA s <> replicateChar n ' ' + , prefixLen = prefixLen s + n + } -- prefixTrimmedA unchanged: trailing spaces are trimmed _ -> return () - renderList $ intersperse FCarriageReturn (mapMaybe cook lns') - modify $ \s -> s{ prefix = oldPref } + renderList $ intersperse FCarriageReturn (mapMaybe (cook . snd) lns') + modify $ \s -> s{ prefix = oldPref + , prefixA = oldPrefixA + , prefixTrimmedA = oldPrefixTrimmedA + , prefixLen = oldPrefixLen } renderList rest isBreakable :: HasChars a => FlatDoc a -> Bool @@ -961,7 +997,7 @@ -- multilingual plane that do not have emoji in them. -- This works in a narrow context. updateMatchStateNarrow :: MatchState -> Char -> MatchState -updateMatchStateNarrow (MatchState firstChar tot _ tentative) !c +updateMatchStateNarrow (MatchState firstChar tot lastChar tentative) !c -- Control characters have width 0: friends don't let friends use tabs | c <= '\x001F' = controlState -- ASCII @@ -1062,12 +1098,44 @@ | c == '\x0BCD' -> combiningState -- Vowel markers | c <= '\x0BCC' -> narrowState -- Main Tamil abugida | otherwise -> narrowState -- Tamil digits and others + -- Thai + | c >= '\x0E00' && c <= '\x0E7F' = + if | c == '\x0E31' -> combiningState -- Mai han akat + | c >= '\x0E34' && c <= '\x0E3A' -> combiningState -- Vowels and tone marks + | c >= '\x0E47' && c <= '\x0E4E' -> combiningState -- Mai tai ku and other marks + | otherwise -> narrowState -- Thai consonants, vowels, digits, symbols + -- Zero-width joiner: joins two emoji together + | c == '\x200D' = + let isLastCharEmojiLike = isJust (IM.lookup (ord lastChar) emojiMap) + || lastChar == '\xFE0F' + || isSkinToneModifier lastChar + in if isLastCharEmojiLike + then MatchState False (tot - 2) c 2 + else controlState + -- Emoji presentation variation selector + | c == '\xFE0F' = + case IM.lookup (ord lastChar) emojiMap of + Just (EmojiInfo True _) -> MatchState False tot c 2 + _ -> controlState + -- CJK Compatibility Ideographs + | c >= '\xF900' && c <= '\xFAFF' = wideState + -- Fullwidth forms + | c >= '\xFF01' && c <= '\xFF60' = wideState + | c >= '\xFFE0' && c <= '\xFFE6' = wideState + -- Supplementary CJK: Extension B and beyond + | c >= '\x20000' && c <= '\x3FFFF' = wideState + -- Emoji skin tone modifiers + | c >= '\x1F3FB' && c <= '\x1F3FF' = + case IM.lookup (ord lastChar) emojiMap of + Just (EmojiInfo _ True) -> MatchState False tot c 2 + _ -> wideState where - narrowState = MatchState False (tot + tentative) c 1 - wideState = MatchState False (tot + tentative) c 2 - combiningState = let w = if firstChar then 1 else 0 in MatchState False (tot + tentative) c w - controlState = MatchState False (tot + tentative) c 0 - ambiguousState = MatchState False (tot + tentative) c 1 + tot' = tot + tentative + narrowState = MatchState False tot' c 1 + wideState = MatchState False tot' c 2 + combiningState = let w = if firstChar then 1 else 0 in MatchState False tot' c w + controlState = MatchState False tot' c 0 + ambiguousState = MatchState False tot' c 1 updateMatchStateNarrow s c = updateMatchStateNoShortcut s c -- | Update a 'MatchState' by processing a character. @@ -1075,7 +1143,7 @@ -- multilingual plane that do not have emoji in them. -- This works in a wide context. updateMatchStateWide :: MatchState -> Char -> MatchState -updateMatchStateWide (MatchState firstChar tot _ tentative) !c +updateMatchStateWide (MatchState firstChar tot lastChar tentative) !c -- Control characters have width 0: friends don't let friends use tabs | c <= '\x001F' = controlState -- ASCII @@ -1163,12 +1231,44 @@ | c == '\x0BCD' -> combiningState -- Vowel markers | c <= '\x0BCC' -> narrowState -- Main Tamil abugida | otherwise -> narrowState -- Tamil digits and others + -- Thai + | c >= '\x0E00' && c <= '\x0E7F' = + if | c == '\x0E31' -> combiningState -- Mai han akat + | c >= '\x0E34' && c <= '\x0E3A' -> combiningState -- Vowels and tone marks + | c >= '\x0E47' && c <= '\x0E4E' -> combiningState -- Mai tai ku and other marks + | otherwise -> narrowState -- Thai consonants, vowels, digits, symbols + -- Zero-width joiner: joins two emoji together + | c == '\x200D' = + let isLastCharEmojiLike = isJust (IM.lookup (ord lastChar) emojiMap) + || lastChar == '\xFE0F' + || isSkinToneModifier lastChar + in if isLastCharEmojiLike + then MatchState False (tot - 2) c 2 + else controlState + -- Emoji presentation variation selector + | c == '\xFE0F' = + case IM.lookup (ord lastChar) emojiMap of + Just (EmojiInfo True _) -> MatchState False tot c 2 + _ -> controlState + -- CJK Compatibility Ideographs + | c >= '\xF900' && c <= '\xFAFF' = wideState + -- Fullwidth forms + | c >= '\xFF01' && c <= '\xFF60' = wideState + | c >= '\xFFE0' && c <= '\xFFE6' = wideState + -- Supplementary CJK: Extension B and beyond + | c >= '\x20000' && c <= '\x3FFFF' = wideState + -- Emoji skin tone modifiers + | c >= '\x1F3FB' && c <= '\x1F3FF' = + case IM.lookup (ord lastChar) emojiMap of + Just (EmojiInfo _ True) -> MatchState False tot c 2 + _ -> wideState where - narrowState = MatchState False (tot + tentative) c 1 - wideState = MatchState False (tot + tentative) c 2 - combiningState = let w = if firstChar then 1 else 0 in MatchState False (tot + tentative) c w - controlState = MatchState False (tot + tentative) c 0 - ambiguousState = MatchState False (tot + tentative) c 2 + tot' = tot + tentative + narrowState = MatchState False tot' c 1 + wideState = MatchState False tot' c 2 + combiningState = let w = if firstChar then 1 else 0 in MatchState False tot' c w + controlState = MatchState False tot' c 0 + ambiguousState = MatchState False tot' c 2 updateMatchStateWide s c = updateMatchStateNoShortcutWide s c -- | Update a 'MatchState' by processing a character, without taking any
