blob: 277e1a16ef633fe0b2f15d3d1a7213d3de8afdf4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE PatternGuards #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Blessings.Text.WCWidth
( module Blessings
) where
import Blessings
import Blessings.Internal
import Data.Char.WCWidth qualified as WCWidth
import Data.Text (Text)
import Data.Text qualified as Text
instance Blessable Text where
length = length'
drop = drop'
take = take'
splitAt = splitAt'
intercalate = Text.intercalate
fromWord8 = Text.pack . show
length' :: Text -> Int
length' = Text.foldr ((+) . wcwidth') 0
drop' :: Int -> Text -> Text
drop' k t =
if k <= 0
then t
else
case Text.uncons t of
Just (c, t') ->
drop' (k - wcwidth' c) t'
Nothing -> mempty
take' :: Int -> Text -> Text
take' k0 =
Text.pack . rec k0
where
rec k t =
if | Just (c, t') <- Text.uncons t, nc <- wcwidth' c, nc <= k ->
c : rec (k - nc) t'
| otherwise ->
[]
splitAt' :: Int -> Text -> (Text, Text)
splitAt' k0 =
rec k0 mempty
where
rec k a t =
if | Just (c, t') <- Text.uncons t, nc <- wcwidth' c, nc <= k ->
rec (k - nc) (c : a) t'
| otherwise ->
(Text.pack $ reverse a, t)
-- TODO this breaks when WCWidth.wcwidth returns -1, which happens for
-- non-printable characters like '\n'.
-- Following wcwidth' isn't entirely correct because WCWidth.wcwidth '\0' == 0
wcwidth' :: Char -> Int
wcwidth' = max 1 . WCWidth.wcwidth
|