module Blammo.Logging.Terminal.LogPiece
  ( LogPiece
  , logPiece
  , render
  , visibleLength
  , bytestring

    -- * Built-in pieces
  , offset
  ) where

import Prelude

import Data.ByteString (ByteString)
import Data.Semigroup (Sum (..))
import Data.String (IsString (..))
import Data.Text (Text, pack)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)

data LogPiece = LogPiece
  { LogPiece -> Text
lpRendered :: Text
  , LogPiece -> Sum Int
lpVisibleLength :: Sum Int
  }

-- TODO: When we drop support for ghc-8.6:
-- deriving stock Generic
-- deriving (Semigroup, Monoid) via (GenericSemigroupMonoid LogPiece)

instance Semigroup LogPiece where
  LogPiece
a <> :: LogPiece -> LogPiece -> LogPiece
<> LogPiece
b =
    LogPiece
      { lpRendered :: Text
lpRendered = LogPiece -> Text
lpRendered LogPiece
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> LogPiece -> Text
lpRendered LogPiece
b
      , lpVisibleLength :: Sum Int
lpVisibleLength = LogPiece -> Sum Int
lpVisibleLength LogPiece
a Sum Int -> Sum Int -> Sum Int
forall a. Semigroup a => a -> a -> a
<> LogPiece -> Sum Int
lpVisibleLength LogPiece
b
      }

instance Monoid LogPiece where
  mempty :: LogPiece
mempty = Text -> Sum Int -> LogPiece
LogPiece Text
forall a. Monoid a => a
mempty Sum Int
forall a. Monoid a => a
mempty

instance IsString LogPiece where
  fromString :: String -> LogPiece
fromString = (Text -> Text) -> Text -> LogPiece
logPiece Text -> Text
forall a. a -> a
id (Text -> LogPiece) -> (String -> Text) -> String -> LogPiece
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack

logPiece
  :: (Text -> Text)
  -- ^ Non-visible decoration, such as color escapes
  -> Text
  -- ^ Raw
  -> LogPiece
logPiece :: (Text -> Text) -> Text -> LogPiece
logPiece Text -> Text
f Text
t =
  LogPiece {lpRendered :: Text
lpRendered = Text -> Text
f Text
t, lpVisibleLength :: Sum Int
lpVisibleLength = Int -> Sum Int
forall a. a -> Sum a
Sum (Int -> Sum Int) -> Int -> Sum Int
forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
t}

render :: LogPiece -> Text
render :: LogPiece -> Text
render = LogPiece -> Text
lpRendered

bytestring :: LogPiece -> ByteString
bytestring :: LogPiece -> ByteString
bytestring = Text -> ByteString
encodeUtf8 (Text -> ByteString)
-> (LogPiece -> Text) -> LogPiece -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogPiece -> Text
render

visibleLength :: LogPiece -> Int
visibleLength :: LogPiece -> Int
visibleLength = Sum Int -> Int
forall a. Sum a -> a
getSum (Sum Int -> Int) -> (LogPiece -> Sum Int) -> LogPiece -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogPiece -> Sum Int
lpVisibleLength

offset :: Int -> LogPiece
offset :: Int -> LogPiece
offset Int
n = LogPiece {lpRendered :: Text
lpRendered = Int -> Text -> Text
T.replicate Int
n Text
" ", lpVisibleLength :: Sum Int
lpVisibleLength = Int -> Sum Int
forall a. a -> Sum a
Sum Int
n}