packages feed

herms-1.9.0.4: src/RichText.hs

{-# LANGUAGE ExistentialQuantification, FlexibleInstances #-}
module RichText (
  Color(..), Text, RichText,
  (~~), bgColor, bold, fontColor, putText, putTextLn
) where

import Data.String
import System.Console.ANSI
import System.IO

class Text t where
  toStr :: Bool -> t -> String

instance Text [Char] where
  toStr _ t = t

data RichText = forall t1 t2. (Text t1, Text t2) => Append t1 t2
              | forall t. Text t                 => BgColor Color t
              | forall t. Text t                 => Bold t
              | forall t. Text t                 => FontColor Color t
              | forall t. Text t                 => Plain t

instance IsString RichText where
  fromString = Plain

instance Text RichText where
  toStr formatted = toStr'
    where
      toStr' (Append t1 t2) = toStr formatted t1 ++ toStr formatted t2
      toStr' (BgColor color t) = wrap (SetColor Background Dull color) t
      toStr' (Bold t) = wrap (SetConsoleIntensity BoldIntensity) t
      toStr' (FontColor color t) = wrap (SetColor Foreground Vivid color) t
      toStr' (Plain t) = toStr formatted t
      wrap code t
        | formatted = setSGRCode [code] ++ s ++ setSGRCode [Reset]
        | otherwise = s
        where s = toStr formatted t

(~~) :: forall t1 t2. (Text t1, Text t2) => t1 -> t2 -> RichText
(~~) = Append

bgColor :: forall s. Text s => Color -> s -> RichText
bgColor = BgColor

bold :: forall s. Text s => s -> RichText
bold = Bold

fontColor :: forall s. Text s => Color -> s -> RichText
fontColor = FontColor

putText :: forall t. Text t => t -> IO ()
putText t = do
  -- We don't want to output ANSI codes if STDOUT is being redirected to a file,
  -- so we check if STDOUT is a terminal that supports ANSI.
  supports <- hSupportsANSI stdout
  putStr $ toStr supports t

putTextLn :: forall t. Text t => t -> IO ()
putTextLn t = putText t >> putStrLn ""