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

Reply via email to