on master help sign in
Improve space performance of text width functions

This change introduces new text width functions to avoid intermediate text/string conversions: * Graphics.Text.Width.wctwidth * Graphics.Text.Width.wctlwidth * Graphics.Text.Width.safeWctwidth * Graphics.Text.Width.safeWctlwidth The 't' versions are for Data.Text and 'tl' are for Data.Text.Lazy. This change also updates the string variants to use foldl' instead of (map . sum).

commitd64ff960271f3a9d1c8b6fd4d4e69c873dbb2d22 authorJonathan Daugherty <cygnus@foobox.com> dateWed 28 Nov 2018, 11:08 (8 years ago) parentec7b51e
4 files changed+36−7
src/Graphics/Text/Width.hs+26−2 src/Graphics/Vty/Image.hs+6−2 src/Graphics/Vty/PictureToSpans.hs+2−1 src/Graphics/Vty/Span.hs+2−2
src/Graphics/Text/Width.hs+26−2
@@ -4,15 +4,29 @@
44module Graphics.Text.Width
55 ( wcwidth
66 , wcswidth
7+ , wctwidth
8+ , wctlwidth
79 , safeWcwidth
810 , safeWcswidth
11+ , safeWctwidth
12+ , safeWctlwidth
913 )
1014where
1115
16+import Data.List (foldl')
17+import qualified Data.Text as T
18+import qualified Data.Text.Lazy as TL
19+
1220foreign import ccall unsafe "vty_mk_wcwidth" wcwidth :: Char -> Int
1321
1422wcswidth :: String -> Int
15−wcswidth = sum . map wcwidth
23+wcswidth = foldl' (\l c -> wcwidth c + l) 0
24+
25+wctwidth :: T.Text -> Int
26+wctwidth = T.foldl' (\l c -> wcwidth c + l) 0
27+
28+wctlwidth :: TL.Text -> Int
29+wctlwidth = TL.foldl' (\l c -> wcwidth c + l) 0
1630
1731-- XXX: Characters with unknown widths occupy 1 column?
1832--
@@ -30,4 +44,14 @@ safeWcwidth = max 0 . wcwidth
3044-- | Returns the display width of a string. Assumes all characters with
3145-- unknown widths are 0 width.
3246safeWcswidth :: String -> Int
33−safeWcswidth = sum . map safeWcwidth
47+safeWcswidth = foldl' (\l c -> safeWcwidth c + l) 0
48+
49+-- | Returns the display width of a text. Assumes all characters with
50+-- unknown widths are 0 width.
51+safeWctwidth :: T.Text -> Int
52+safeWctwidth = T.foldl' (\l c -> safeWcwidth c + l) 0
53+
54+-- | Returns the display width of a lazy text. Assumes all characters
55+-- with unknown widths are 0 width.
56+safeWctlwidth :: TL.Text -> Int
57+safeWctlwidth = TL.foldl' (\l c -> safeWcwidth c + l) 0
src/Graphics/Vty/Image.hs+6−2
@@ -46,8 +46,12 @@ module Graphics.Vty.Image
4646 -- * Character width functions
4747 , safeWcwidth
4848 , safeWcswidth
49+ , safeWctwidth
50+ , safeWctlwidth
4951 , wcwidth
5052 , wcswidth
53+ , wctwidth
54+ , wctlwidth
5155 -- * Display Regions
5256 , DisplayText
5357 , DisplayRegion
@@ -116,13 +120,13 @@ vertCat = foldr vertJoin EmptyImage
116120-- | Make an 'Image' from a lazy text value. This function should not be
117121-- given a text value containing escapes.
118122text :: Attr -> TL.Text -> Image
119−text a txt = let displayWidth = safeWcswidth (TL.unpack txt)
123+text a txt = let displayWidth = safeWctlwidth txt
120124 in HorizText a txt displayWidth (fromIntegral $! TL.length txt)
121125
122126-- | Make an 'Image' from a text value. This function should not be
123127-- given a text value containing escapes.
124128text' :: Attr -> T.Text -> Image
125−text' a txt = let displayWidth = safeWcswidth (T.unpack txt)
129+text' a txt = let displayWidth = safeWctwidth txt
126130 in HorizText a (TL.fromStrict txt) displayWidth (T.length txt)
127131
128132-- | Make an image from a single character. This is a standard Haskell
src/Graphics/Vty/PictureToSpans.hs+2−1
@@ -13,6 +13,7 @@ import Graphics.Vty.Image
1313import Graphics.Vty.Image.Internal
1414import Graphics.Vty.Picture
1515import Graphics.Vty.Span
16+import Graphics.Text.Width (wctlwidth)
1617
1718import Lens.Micro
1819import Lens.Micro.Mtl
@@ -323,7 +324,7 @@ addUnclippedText a txt = do
323324 let op = TextSpan a usedDisplayColumns
324325 (fromIntegral $ TL.length txt)
325326 txt
326− usedDisplayColumns = wcswidth $ TL.unpack txt
327+ usedDisplayColumns = wctlwidth txt
327328 use rowOffset >>= snocOp op
328329
329330addRowCompletion :: DisplayRegion -> Int -> BlitM s ()
src/Graphics/Vty/Span.hs+2−2
@@ -14,6 +14,7 @@ module Graphics.Vty.Span where
1414import Graphics.Vty.Attributes (Attr)
1515import Graphics.Vty.Image
1616import Graphics.Vty.Image.Internal ( clipText )
17+import Graphics.Text.Width (wctlwidth)
1718
1819import qualified Data.Text.Lazy as TL
1920import Data.Vector (Vector)
@@ -126,7 +127,6 @@ spanOpHasWidth (RowEnd ow) = Just (ow,ow)
126127-- span op.
127128columnsToCharOffset :: Int -> SpanOp -> Int
128129columnsToCharOffset cx (TextSpan _ _ _ utf8Str) =
129− let str = TL.unpack utf8Str
130− in wcswidth (take cx str)
130+ wctlwidth (TL.take (fromIntegral cx) utf8Str)
131131columnsToCharOffset cx (Skip _) = cx
132132columnsToCharOffset cx (RowEnd _) = cx