symantic-document-1.2.2.20190627: Symantic/Document/AnsiText.hs
{-# LANGUAGE UndecidableInstances #-}
module Symantic.Document.AnsiText where
import Control.Applicative (Applicative(..), liftA2)
import Control.Monad (Monad(..), sequence)
import Control.Monad.Trans.Reader
import Data.Bool
import Data.Char (Char)
import Data.Function (($), (.), id)
import Data.Functor ((<$>))
import Data.Monoid (Monoid(..))
import Data.Semigroup (Semigroup(..))
import Data.String (String, IsString(..))
import Data.Text (Text)
import System.Console.ANSI
import Text.Show (Show(..))
import qualified Data.List as List
import qualified Data.Text.Lazy as TL
import Symantic.Document.API
-- * Type 'AnsiText'
newtype AnsiText d = AnsiText { unAnsiText :: Reader [SGR] d }
instance Show d => Show (AnsiText d) where
show (AnsiText d) = show $ runReader d []
ansiText :: AnsiText d -> AnsiText d
ansiText = id
runAnsiText :: AnsiText d -> d
runAnsiText (AnsiText d) = (`runReader` []) d
instance From Char d => From Char (AnsiText d) where
from = AnsiText . return . from
instance From String d => From String (AnsiText d) where
from = AnsiText . return . from
instance From Text d => From Text (AnsiText d) where
from = AnsiText . return . from
instance From TL.Text d => From TL.Text (AnsiText d) where
from = AnsiText . return . from
instance From s (AnsiText d) => From (Line s) (AnsiText d) where
from = from . unLine
instance From s (AnsiText d) => From (Word s) (AnsiText d) where
from = from . unWord
instance From String d => IsString (AnsiText d) where
fromString = from
instance Semigroup d => Semigroup (AnsiText d) where
AnsiText x <> AnsiText y = AnsiText $ liftA2 (<>) x y
instance Monoid d => Monoid (AnsiText d) where
mempty = AnsiText (return mempty)
mappend = (<>)
instance Lengthable d => Lengthable (AnsiText d) where
-- NOTE: AnsiText's Reader can be run with an empty value
-- because all 'SGR' are ignored anyway.
width (AnsiText ds) = width $ runReader ds mempty
nullWidth (AnsiText ds) = nullWidth $ runReader ds mempty
instance Spaceable d => Spaceable (AnsiText d) where
newline = AnsiText $ return newline
space = AnsiText $ return space
spaces = AnsiText . return . spaces
instance (Semigroup d, From [SGR] d) => Colorable16 (AnsiText d) where
reverse = ansiTextSGR $ SetSwapForegroundBackground True
black = ansiTextSGR $ SetColor Foreground Dull Black
red = ansiTextSGR $ SetColor Foreground Dull Red
green = ansiTextSGR $ SetColor Foreground Dull Green
yellow = ansiTextSGR $ SetColor Foreground Dull Yellow
blue = ansiTextSGR $ SetColor Foreground Dull Blue
magenta = ansiTextSGR $ SetColor Foreground Dull Magenta
cyan = ansiTextSGR $ SetColor Foreground Dull Cyan
white = ansiTextSGR $ SetColor Foreground Dull White
blacker = ansiTextSGR $ SetColor Foreground Vivid Black
redder = ansiTextSGR $ SetColor Foreground Vivid Red
greener = ansiTextSGR $ SetColor Foreground Vivid Green
yellower = ansiTextSGR $ SetColor Foreground Vivid Yellow
bluer = ansiTextSGR $ SetColor Foreground Vivid Blue
magentaer = ansiTextSGR $ SetColor Foreground Vivid Magenta
cyaner = ansiTextSGR $ SetColor Foreground Vivid Cyan
whiter = ansiTextSGR $ SetColor Foreground Vivid White
onBlack = ansiTextSGR $ SetColor Background Dull Black
onRed = ansiTextSGR $ SetColor Background Dull Red
onGreen = ansiTextSGR $ SetColor Background Dull Green
onYellow = ansiTextSGR $ SetColor Background Dull Yellow
onBlue = ansiTextSGR $ SetColor Background Dull Blue
onMagenta = ansiTextSGR $ SetColor Background Dull Magenta
onCyan = ansiTextSGR $ SetColor Background Dull Cyan
onWhite = ansiTextSGR $ SetColor Background Dull White
onBlacker = ansiTextSGR $ SetColor Background Vivid Black
onRedder = ansiTextSGR $ SetColor Background Vivid Red
onGreener = ansiTextSGR $ SetColor Background Vivid Green
onYellower = ansiTextSGR $ SetColor Background Vivid Yellow
onBluer = ansiTextSGR $ SetColor Background Vivid Blue
onMagentaer = ansiTextSGR $ SetColor Background Vivid Magenta
onCyaner = ansiTextSGR $ SetColor Background Vivid Cyan
onWhiter = ansiTextSGR $ SetColor Background Vivid White
instance (Semigroup d, From [SGR] d) => Decorable (AnsiText d) where
bold = ansiTextSGR $ SetConsoleIntensity BoldIntensity
underline = ansiTextSGR $ SetUnderlining SingleUnderline
italic = ansiTextSGR $ SetItalicized True
instance Justifiable d => Justifiable (AnsiText d) where
justify (AnsiText d) = AnsiText $ justify <$> d
instance Indentable d => Indentable (AnsiText d) where
setIndent i (AnsiText d) = AnsiText $ setIndent i <$> d
incrIndent i (AnsiText d) = AnsiText $ incrIndent i <$> d
fill w (AnsiText d) = AnsiText $ fill w <$> d
breakfill w (AnsiText d) = AnsiText $ breakfill w <$> d
align (AnsiText d) = AnsiText $ align <$> d
instance Listable d => Listable (AnsiText d) where
ul ds = AnsiText $ (ul <$>) $ sequence $ unAnsiText <$> ds
ol ds = AnsiText $ (ol <$>) $ sequence $ unAnsiText <$> ds
instance Wrappable d => Wrappable (AnsiText d) where
setWidth w (AnsiText d) = AnsiText $ setWidth w <$> d
breakpoint = AnsiText $ return breakpoint
breakspace = AnsiText $ return breakspace
breakalt (AnsiText x) (AnsiText y) = AnsiText $ liftA2 breakalt x y
ansiTextSGR ::
Semigroup d => From [SGR] d =>
SGR -> AnsiText d -> AnsiText d
ansiTextSGR newSGR (AnsiText d) = AnsiText $ do
oldSGR <- ask
(\m -> from [newSGR] <> m <> from (Reset:List.reverse oldSGR))
<$> local (newSGR :) d
-- * Type 'PlainText'
-- | Drop 'Colorable16' and 'Decorable'.
newtype PlainText d = PlainText { unPlainText :: d }
deriving (Show)
plainText :: PlainText d -> PlainText d
plainText = id
runPlainText :: PlainText d -> d
runPlainText (PlainText d) = d
instance From Char d => From Char (PlainText d) where
from = PlainText . from
instance From String d => From String (PlainText d) where
from = PlainText . from
instance From Text d => From Text (PlainText d) where
from = PlainText . from
instance From TL.Text d => From TL.Text (PlainText d) where
from = PlainText . from
instance From s (PlainText d) => From (Line s) (PlainText d) where
from = from . unLine
instance From s (PlainText d) => From (Word s) (PlainText d) where
from = from . unWord
instance From String d => IsString (PlainText d) where
fromString = from
instance Semigroup d => Semigroup (PlainText d) where
PlainText x <> PlainText y = PlainText $ (<>) x y
instance Monoid d => Monoid (PlainText d) where
mempty = PlainText mempty
mappend = (<>)
instance Lengthable d => Lengthable (PlainText d) where
-- NOTE: PlainText's Reader can be run with an empty value
-- because all 'SGR' are ignored anyway.
width (PlainText ds) = width ds
nullWidth (PlainText ds) = nullWidth ds
instance Spaceable d => Spaceable (PlainText d) where
newline = PlainText $ newline
space = PlainText $ space
spaces = PlainText . spaces
instance Semigroup d => Colorable16 (PlainText d) where
reverse = plainTextSGR
black = plainTextSGR
red = plainTextSGR
green = plainTextSGR
yellow = plainTextSGR
blue = plainTextSGR
magenta = plainTextSGR
cyan = plainTextSGR
white = plainTextSGR
blacker = plainTextSGR
redder = plainTextSGR
greener = plainTextSGR
yellower = plainTextSGR
bluer = plainTextSGR
magentaer = plainTextSGR
cyaner = plainTextSGR
whiter = plainTextSGR
onBlack = plainTextSGR
onRed = plainTextSGR
onGreen = plainTextSGR
onYellow = plainTextSGR
onBlue = plainTextSGR
onMagenta = plainTextSGR
onCyan = plainTextSGR
onWhite = plainTextSGR
onBlacker = plainTextSGR
onRedder = plainTextSGR
onGreener = plainTextSGR
onYellower = plainTextSGR
onBluer = plainTextSGR
onMagentaer = plainTextSGR
onCyaner = plainTextSGR
onWhiter = plainTextSGR
instance Semigroup d => Decorable (PlainText d) where
bold = plainTextSGR
underline = plainTextSGR
italic = plainTextSGR
instance Justifiable d => Justifiable (PlainText d) where
justify (PlainText d) = PlainText $ justify d
instance Indentable d => Indentable (PlainText d) where
setIndent i (PlainText d) = PlainText $ setIndent i d
incrIndent i (PlainText d) = PlainText $ incrIndent i d
fill w (PlainText d) = PlainText $ fill w d
breakfill w (PlainText d) = PlainText $ breakfill w d
align (PlainText d) = PlainText $ align d
instance Listable d => Listable (PlainText d) where
ul ds = PlainText $ ul $ unPlainText <$> ds
ol ds = PlainText $ ol $ unPlainText <$> ds
instance Wrappable d => Wrappable (PlainText d) where
setWidth w (PlainText d) = PlainText $ setWidth w d
breakpoint = PlainText breakpoint
breakspace = PlainText breakspace
breakalt (PlainText x) (PlainText y) = PlainText $ breakalt x y
plainTextSGR ::
Semigroup d =>
PlainText d -> PlainText d
plainTextSGR (PlainText d) = PlainText d