{-# LANGUAGE DeriveGeneric, DeriveDataTypeable, DeriveFunctor, DeriveTraversable, DeriveFoldable, TemplateHaskell #-} -- | All the main types in Rainbow. Using this module you can specify -- that you want different formatting for 8- and 256-color terminals. -- Many of the names in this module conflict with the names in -- "Rainbow", so it's probably best to @import@ this module -- @qualified@. module Rainbow.Types where -- # Imports import Control.Lens (makeLenses) import Data.String (IsString(..)) import Data.Text (Text) import qualified Data.Text as X import Data.Traversable () import Data.Typeable (Typeable) import Data.Word (Word8) import GHC.Generics (Generic) -- -- Colors -- -- | A color; a 'Nothing' value means that the terminal's default -- color is used. The type of the 'Maybe' generally will be an -- 'Enum8' to represent one of 8 colors, or a 'Word8' to represent one -- of 256 colors. newtype Color a = Color (Maybe a) deriving (Eq, Show, Ord, Generic, Typeable, Functor, Foldable, Traversable) instance Semigroup (Color a) where Color x <> Color y = case y of Just a -> Color (Just a) _ -> Color x -- | Takes the last non-Nothing Color. 'mempty' is no color. instance Monoid (Color a) where mempty = Color Nothing -- | A simple enumeration for eight values. Represents eight colors. data Enum8 = E0 | E1 | E2 | E3 | E4 | E5 | E6 | E7 deriving (Eq, Ord, Show, Bounded, Enum, Generic, Typeable) enum8toWord8 :: Enum8 -> Word8 enum8toWord8 e = case e of E0 -> 0 E1 -> 1 E2 -> 2 E3 -> 3 E4 -> 4 E5 -> 5 E6 -> 6 E7 -> 7 black :: Enum8 black = E0 red :: Enum8 red = E1 green :: Enum8 green = E2 yellow :: Enum8 yellow = E3 blue :: Enum8 blue = E4 magenta :: Enum8 magenta = E5 cyan :: Enum8 cyan = E6 white :: Enum8 white = E7 grey :: Word8 grey = 8 brightRed :: Word8 brightRed = 9 brightGreen :: Word8 brightGreen = 10 brightYellow :: Word8 brightYellow = 11 brightBlue :: Word8 brightBlue = 12 brightMagenta :: Word8 brightMagenta = 13 brightCyan :: Word8 brightCyan = 14 brightWhite :: Word8 brightWhite = 15 -- -- Styles -- -- | Text formatting such as bold, italic, etc. data Format = Format { _bold :: Bool , _faint :: Bool , _italic :: Bool , _underline :: Bool , _blink :: Bool , _inverse :: Bool , _invisible :: Bool , _strikeout :: Bool } deriving (Show, Eq, Ord, Generic, Typeable) makeLenses ''Format instance Semigroup Format where (Format x0 x1 x2 x3 x4 x5 x6 x7) <> (Format y0 y1 y2 y3 y4 y5 y6 y7) = Format (x0 || y0) (x1 || y1) (x2 || y2) (x3 || y3) (x4 || y4) (x5 || y5) (x6 || y6) (x7 || y7) -- | For each field, the resulting field is True if either field is -- True. For 'mempty', every field is False. instance Monoid Format where mempty = Format False False False False False False False False -- | The foreground and background color, and the 'Format'. This -- represents all colors and formatting attributes for either an 8- or -- 256-color terminal. data Style a = Style { _fore :: Color a , _back :: Color a , _format :: Format } deriving (Show, Eq, Ord, Generic, Typeable, Functor, Foldable, Traversable) makeLenses ''Style instance Semigroup (Style a) where (Style x0 x1 x2) <> (Style y0 y1 y2) = Style (x0 <> y0) (x1 <> y1) (x2 <> y2) -- | Uses the underlying 'Monoid' instances for 'Color' and 'Format'. instance Monoid (Style a) where mempty = Style mempty mempty mempty -- -- Scheme -- -- | Holds the 'Style' for both 8- and 256-color terminals. data Scheme = Scheme { _style8 :: Style Enum8 , _style256 :: Style Word8 } deriving (Eq, Ord, Show, Generic, Typeable) makeLenses ''Scheme instance Semigroup Scheme where (Scheme x0 x1) <> (Scheme y0 y1) = Scheme (x0 <> y0) (x1 <> y1) instance Monoid Scheme where mempty = Scheme mempty mempty -- -- Chunks -- -- | A chunk is some textual data coupled with a description of what -- color the text is, attributes like whether it is bold or -- underlined, etc. The chunk knows what foreground and background -- colors and what attributes to use for both an 8 color terminal and -- a 256 color terminal. data Chunk = Chunk { _scheme :: Scheme , _yarn :: Text } deriving (Eq, Show, Ord, Generic, Typeable) -- | Uses the underlying 'Semigroup' instances for both the -- underlying 'Scheme' and the underlying 'Text'. instance Semigroup Chunk where (Chunk x0 x1) <> (Chunk y0 y1) = Chunk (x0 <> y0) (x1 <> y1) -- | Creates a 'Chunk' with no formatting and with the given text. instance IsString Chunk where fromString = chunk . X.pack -- | Uses the underlying 'Monoid' instances for the 'Scheme' and for -- the underlying 'Text'. Therefore 'mempty' will have no -- formatting, no colors, and no text. instance Monoid Chunk where mempty = Chunk mempty mempty -- | Creates a 'Chunk' with no formatting and with the given text. -- A 'Chunk' is also an instance of 'Data.String.IsString' so you -- can create them with the @OverloadedStrings@ extension. Such a -- 'Chunk' has the text of the string and no formatting. chunk :: Text -> Chunk chunk = Chunk mempty makeLenses ''Chunk -- | Stores colors that may affect 8-color terminals, 256-color -- terminals, both, or neither. data Radiant = Radiant { _color8 :: Color Enum8 , _color256 :: Color Word8 } deriving (Eq, Ord, Show, Typeable, Generic) instance Semigroup Radiant where (Radiant x0 x1) <> (Radiant y0 y1) = Radiant (x0 <> y0) (x1 <> y1) -- | Uses the underlying 'Monoid' instance for the 'Color's. Thus the -- last non-'Nothing' 'Color' is used. This can be useful to specify -- one color for 8-color terminals and a different color for 256-color -- terminals. instance Monoid Radiant where mempty = Radiant mempty mempty makeLenses ''Radiant