{-# LANGUAGE TupleSections #-}
module Graphics.Vty.UnicodeWidthTable.Query
( buildUnicodeWidthTable
, defaultUnicodeTableUpperBound
)
where
import Control.Monad (forM)
import Data.Char (generalCategory, GeneralCategory(..))
import System.Console.ANSI (getCursorPosition)
import Text.Printf (printf)
import Graphics.Vty.UnicodeWidthTable.Types
shouldConsider :: Char -> Bool
shouldConsider :: Char -> Bool
shouldConsider Char
c =
case Char -> GeneralCategory
generalCategory Char
c of
GeneralCategory
Control -> Bool
False
GeneralCategory
NotAssigned -> Bool
False
GeneralCategory
Surrogate -> Bool
False
GeneralCategory
_ -> Bool
True
charWidth :: Char -> IO Int
charWidth :: Char -> IO Int
charWidth Char
c = do
forall r. PrintfType r => String -> r
printf String
"\r"
Char -> IO ()
putChar Char
c
Just (Int
_, Int
col) <- IO (Maybe (Int, Int))
getCursorPosition
forall (m :: * -> *) a. Monad m => a -> m a
return Int
col
mkRanges :: [(Char, Int)] -> [WidthTableRange]
mkRanges :: [(Char, Int)] -> [WidthTableRange]
mkRanges [(Char, Int)]
pairs =
let convertedPairs :: [(Word32, Word8)]
convertedPairs = forall {a} {a} {b} {a}.
(Integral a, Num a, Num b, Enum a) =>
(a, a) -> (a, b)
convert forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Char, Int)]
pairs
convert :: (a, a) -> (a, b)
convert (a
c, a
i) = (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> Int
fromEnum a
c, forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i)
go :: Maybe WidthTableRange
-> [WidthTableRange] -> [(Word32, Word8)] -> [WidthTableRange]
go Maybe WidthTableRange
Nothing [WidthTableRange]
finishedRanges [] = [WidthTableRange]
finishedRanges
go (Just WidthTableRange
r) [WidthTableRange]
finishedRanges [] = WidthTableRange
rforall a. a -> [a] -> [a]
:[WidthTableRange]
finishedRanges
go Maybe WidthTableRange
Nothing [WidthTableRange]
finishedRanges ((Word32
c, Word8
width):[(Word32, Word8)]
rest) =
Maybe WidthTableRange
-> [WidthTableRange] -> [(Word32, Word8)] -> [WidthTableRange]
go (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Word32 -> Word32 -> Word8 -> WidthTableRange
WidthTableRange Word32
c Word32
1 Word8
width) [WidthTableRange]
finishedRanges [(Word32, Word8)]
rest
go (Just r :: WidthTableRange
r@(WidthTableRange Word32
prevCh Word32
sz Word8
prevWidth)) [WidthTableRange]
finishedRanges ((Word32
c, Word8
width):[(Word32, Word8)]
rest) =
if Word32
c forall a. Eq a => a -> a -> Bool
== Word32
prevCh forall a. Num a => a -> a -> a
+ Word32
sz Bool -> Bool -> Bool
&& Word8
prevWidth forall a. Eq a => a -> a -> Bool
== Word8
width
then Maybe WidthTableRange
-> [WidthTableRange] -> [(Word32, Word8)] -> [WidthTableRange]
go (forall a. a -> Maybe a
Just (Word32 -> Word32 -> Word8 -> WidthTableRange
WidthTableRange Word32
prevCh (Word32
sz forall a. Num a => a -> a -> a
+ Word32
1) Word8
prevWidth)) [WidthTableRange]
finishedRanges [(Word32, Word8)]
rest
else Maybe WidthTableRange
-> [WidthTableRange] -> [(Word32, Word8)] -> [WidthTableRange]
go (forall a. a -> Maybe a
Just (Word32 -> Word32 -> Word8 -> WidthTableRange
WidthTableRange Word32
c Word32
1 Word8
width)) (WidthTableRange
rforall a. a -> [a] -> [a]
:[WidthTableRange]
finishedRanges) [(Word32, Word8)]
rest
in Maybe WidthTableRange
-> [WidthTableRange] -> [(Word32, Word8)] -> [WidthTableRange]
go forall a. Maybe a
Nothing [] [(Word32, Word8)]
convertedPairs
defaultUnicodeTableUpperBound :: Char
defaultUnicodeTableUpperBound :: Char
defaultUnicodeTableUpperBound = Char
'\xe0000'
buildUnicodeWidthTable :: Char -> IO UnicodeWidthTable
buildUnicodeWidthTable :: Char -> IO UnicodeWidthTable
buildUnicodeWidthTable Char
tableUpperBound = do
[(Char, Int)]
pairs <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (forall a. (a -> Bool) -> [a] -> [a]
filter Char -> Bool
shouldConsider [Char
'\0'..Char
tableUpperBound]) forall a b. (a -> b) -> a -> b
$ \Char
i ->
(Char
i,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> IO Int
charWidth Char
i
forall (m :: * -> *) a. Monad m => a -> m a
return UnicodeWidthTable { unicodeWidthTableRanges :: [WidthTableRange]
unicodeWidthTableRanges = forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ [(Char, Int)] -> [WidthTableRange]
mkRanges [(Char, Int)]
pairs
}