    -- Copyright 2009 Corey O'Connor
    {-# OPTIONS_GHC -D_XOPEN_SOURCE #-}
    {-# LANGUAGE ForeignFunctionInterface #-}
    -- | This module provides functions to measure the terminal column width
    -- of characters and strings.
    --
    -- The functions provided in this module all ultimately make calls to
    -- the C implementation in @cbits/mk_wcwidth.c@. That code manages some
    -- global state that carries a table of Unicode character widths. For
    -- more details, see 'Graphics.Vty.UnicodeWidthTable.Install', the C
    -- code, and the "Multi-Column Character Support" section of the project
    -- @README@.
    module Graphics.Text.Width
      ( wcwidth
      , wcswidth
      , wctwidth
      , wctlwidth
      , safeWcwidth
      , safeWcswidth
      , safeWctwidth
      , safeWctlwidth
      )
    where

    import Data.List (foldl')
    import qualified Data.Text as T
    import qualified Data.Text.Lazy as TL

    foreign import ccall unsafe "vty_mk_wcwidth" wcwidth :: Char -> Int

    wcswidth :: String -> Int
    wcswidth :: String -> Int
    wcswidth = (Int -> Char -> Int) -> Int -> String -> Int
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (\Int
    l Char
    c -> Char -> Int
    wcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0
    {-# INLINE [1] wcswidth #-}

    wctwidth :: T.Text -> Int
    wctwidth :: Text -> Int
    wctwidth = (Int -> Char -> Int) -> Int -> Text -> Int
    forall a. (a -> Char -> a) -> a -> Text -> a
    T.foldl' (\Int
    l Char
    c -> Char -> Int
    wcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0

    wctlwidth :: TL.Text -> Int
    wctlwidth :: Text -> Int
    wctlwidth = (Int -> Char -> Int) -> Int -> Text -> Int
    forall a. (a -> Char -> a) -> a -> Text -> a
    TL.foldl' (\Int
    l Char
    c -> Char -> Int
    wcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0

    {-# RULES
    "wcswidth/unpack" forall x. wcswidth (T.unpack x) = wctwidth x
    "wcswidth/lazy-unpack" forall x. wcswidth (TL.unpack x) = wctlwidth x
      #-}

    -- | Returns the display width of a character. Assumes all characters
    -- with unknown widths are 0 width.
    safeWcwidth :: Char -> Int
    safeWcwidth :: Char -> Int
    safeWcwidth = Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    max Int
    0 (Int -> Int) -> (Char -> Int) -> Char -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Char -> Int
    wcwidth

    -- | Returns the display width of a string. Assumes all characters with
    -- unknown widths are 0 width.
    safeWcswidth :: String -> Int
    safeWcswidth :: String -> Int
    safeWcswidth = (Int -> Char -> Int) -> Int -> String -> Int
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (\Int
    l Char
    c -> Char -> Int
    safeWcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0

    -- | Returns the display width of a text. Assumes all characters with
    -- unknown widths are 0 width.
    safeWctwidth :: T.Text -> Int
    safeWctwidth :: Text -> Int
    safeWctwidth = (Int -> Char -> Int) -> Int -> Text -> Int
    forall a. (a -> Char -> a) -> a -> Text -> a
    T.foldl' (\Int
    l Char
    c -> Char -> Int
    safeWcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0

    -- | Returns the display width of a lazy text. Assumes all characters
    -- with unknown widths are 0 width.
    safeWctlwidth :: TL.Text -> Int
    safeWctlwidth :: Text -> Int
    safeWctlwidth = (Int -> Char -> Int) -> Int -> Text -> Int
    forall a. (a -> Char -> a) -> a -> Text -> a
    TL.foldl' (\Int
    l Char
    c -> Char -> Int
    safeWcwidth Char
    c Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    l) Int
    0