packages feed

groot-0.0.1.0: src/Groot/Data/Text/Styled.hs

{-# LANGUAGE OverloadedStrings #-}

module Groot.Data.Text.Styled
     ( Style
     , noStyle
     , blueStyle
     , redStyle
     , yellowStyle
     , greenStyle
     , cyanStyle
     , StyledText
     , styled
     , empty
     , singleton
     , styleless
     , (<+>)
     ) where

import           Control.Monad.IO.Class
import           Data.Foldable
import           Data.Semigroup
import           Data.String
import           Data.Text               (Text)
import qualified Data.Text               as T
import qualified Data.Text.IO            as T
import           Network.AWS.Data.Text
import           System.Console.ANSI

import           Groot.Data.Text.Display

type Style = [SGR]

noStyle, blueStyle, redStyle, yellowStyle, greenStyle, cyanStyle :: Style
noStyle     = [Reset]
blueStyle   = [SetColor Foreground Dull Blue]
redStyle    = [SetColor Foreground Vivid Red]
yellowStyle = [SetColor Foreground Dull Yellow]
greenStyle  = [SetColor Foreground Dull Green]
cyanStyle   = [SetColor Foreground Dull Cyan]

data StyledText =
    TextSpan Style Text
  | TextBlock [StyledText]
  deriving (Eq, Show)

styled :: Style -> Text -> StyledText
styled = TextSpan
{-# INLINE styled #-}

empty :: StyledText
empty = styled noStyle T.empty
{-# INLINE empty #-}

singleton :: Char -> StyledText
singleton ch = styled noStyle (T.singleton ch)
{-# INLINE singleton #-}

styleless :: Text -> StyledText
styleless = styled noStyle
{-# INLINE styleless #-}

instance IsString StyledText where
  fromString str = styled noStyle (T.pack str)

instance Semigroup StyledText where
  lhs@(TextSpan _ _) <> rhs@(TextSpan _ _) = TextBlock [lhs, rhs]
  lhs@(TextSpan _ _) <> (TextBlock bs)     = TextBlock (lhs:bs)
  (TextBlock bs)     <> rhs@(TextSpan _ _) = TextBlock (bs ++ [rhs])
  (TextBlock lhs)    <> (TextBlock rhs)    = TextBlock (lhs ++ rhs)

instance Monoid StyledText where
  mempty = empty
  mappend = (<>)

(<+>) :: StyledText -> StyledText -> StyledText
lhs <+> rhs = lhs <> (singleton ' ') <> rhs

instance ToText StyledText where
  toText (TextSpan _ txt) = txt
  toText (TextBlock xs)   = T.concat $ toText <$> xs

instance Display StyledText where
  display (TextSpan style txt) = liftIO $ do
    setSGR style
    T.putStr txt
  display (TextBlock xs) =
    forM_ xs display