-- | Calculate the width of String and Text, being aware of wide characters.

module Text.WideString (
  -- * Text Builders which keep track of length
  WideBuilder(..),
  wbUnpack,
  wbToText,
  wbFromText
  ) where

import Data.Text (Text)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TB
import Text.DocLayout (realLength)


-- | Helper for constructing Builders while keeping track of text width.
data WideBuilder = WideBuilder
  { WideBuilder -> Builder
wbBuilder :: !TB.Builder
  , WideBuilder -> Int
wbWidth   :: !Int
  } deriving (Int -> WideBuilder -> ShowS
[WideBuilder] -> ShowS
WideBuilder -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WideBuilder] -> ShowS
$cshowList :: [WideBuilder] -> ShowS
show :: WideBuilder -> String
$cshow :: WideBuilder -> String
showsPrec :: Int -> WideBuilder -> ShowS
$cshowsPrec :: Int -> WideBuilder -> ShowS
Show)

instance Semigroup WideBuilder where
  WideBuilder Builder
x Int
i <> :: WideBuilder -> WideBuilder -> WideBuilder
<> WideBuilder Builder
y Int
j = Builder -> Int -> WideBuilder
WideBuilder (Builder
x forall a. Semigroup a => a -> a -> a
<> Builder
y) (Int
i forall a. Num a => a -> a -> a
+ Int
j)

instance Monoid WideBuilder where
  mempty :: WideBuilder
mempty = Builder -> Int -> WideBuilder
WideBuilder forall a. Monoid a => a
mempty Int
0

-- | Convert a WideBuilder to a strict Text.
wbToText :: WideBuilder -> Text
wbToText :: WideBuilder -> Text
wbToText = Text -> Text
TL.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
TB.toLazyText forall b c a. (b -> c) -> (a -> b) -> a -> c
. WideBuilder -> Builder
wbBuilder

-- | Convert a strict Text to a WideBuilder.
wbFromText :: Text -> WideBuilder
wbFromText :: Text -> WideBuilder
wbFromText Text
t = Builder -> Int -> WideBuilder
WideBuilder (Text -> Builder
TB.fromText Text
t) (forall a. HasChars a => a -> Int
realLength Text
t)

-- | Convert a WideBuilder to a String.
wbUnpack :: WideBuilder -> String
wbUnpack :: WideBuilder -> String
wbUnpack = Text -> String
TL.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
TB.toLazyText forall b c a. (b -> c) -> (a -> b) -> a -> c
. WideBuilder -> Builder
wbBuilder