packages feed

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