{-|
Module      : Z.IO.StdStream.Ansi
Description : Ansi control code sequences
Copyright   : (c) Winterland, 2017-2020
License     : BSD
Maintainer  : winterland1989@gmail.com
Stability   : experimental
Portability : non-portable
Provides utilities to build <ANSI code sequences https://en.wikipedia.org/wiki/ANSI_escape_code>.
@
> putStd . bold . italicize . color Red  $ "hello"
hello   -- bold, italicize and red
@
-}

module Z.IO.StdStream.Ansi
  ( -- * Style modifier
    bold, italicize, underline,
    color, color', palette, palette', rgb, rgb',
    -- * Control codes
    cursorUp, cursorDown, cursorForward, cursorBackward,
    cursorDownLine, cursorUpLine ,
    setCursorColumn, setCursorPosition, saveCursor, restoreCursor, getCursorPosition,
    clearFromCursorToScreenEnd, clearFromCursorToScreenBeginning, clearScreen,
    clearFromCursorToLineEnd, clearFromCursorToLineBeginning, clearLine,
    scrollPageUp, scrollPageDown,
    hideCursor, showCursor,
    setTitle,
    -- * Style codes
    reset,
    boldIntensity, faintIntensity, resetIntensity,
    italicized, noItalicized,
    singleUnderline, doubleUnderline, noUnderline,
    slowBlink, rapidBlink, blinkOff,
    conceal, reveal,
    invert, invertOff,
    setForeground, setBrightForeground, setBackground, setBrightBackground,
    setPaletteForeground, setPaletteBackground,
    setRGBForeground, setRGBBackground,
    setDefaultForeground, setDefaultBackground,
    AnsiColor(..), PaletteColor, RGBColor,
    -- * Internal helper
    csi, sgr, colorToCode
  ) where

import Control.Monad
import qualified Z.Data.Builder as B
import qualified Z.Data.Parser as P
import qualified Z.Data.Text    as T
import Z.Data.ASCII
import Data.Word
import GHC.Generics
import Z.IO.StdStream
import Z.IO.Buffered

csi :: [Int]  -- ^ List of parameters for the control sequence
    -> B.Builder () -- ^ Character(s) that identify the control function
    -> B.Builder ()
{-# INLINABLE csi #-}
csi :: [Int] -> Builder () -> Builder ()
csi [Int]
args Builder ()
code = do
    Char -> Builder ()
B.char8 Char
'\ESC'
    Char -> Builder ()
B.char8 Char
'['
    Builder () -> (Int -> Builder ()) -> [Int] -> Builder ()
forall a. Builder () -> (a -> Builder ()) -> [a] -> Builder ()
B.intercalateList (Char -> Builder ()
B.char8 Char
';') Int -> Builder ()
forall a. (Integral a, Bounded a) => a -> Builder ()
B.int [Int]
args
    Builder ()
code

cursorUp, cursorDown, cursorForward, cursorBackward
  :: Int -- ^ Number of lines or characters to move
  -> B.Builder ()
cursorDownLine, cursorUpLine :: Int -- ^ Number of lines to move
                                     -> B.Builder ()
{-# INLINABLE cursorUp #-}
cursorUp :: Int -> Builder ()
cursorUp Int
n       = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'A')
{-# INLINABLE cursorDown #-}
cursorDown :: Int -> Builder ()
cursorDown Int
n     = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'B')
{-# INLINABLE cursorForward #-}
cursorForward :: Int -> Builder ()
cursorForward Int
n  = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'C')
{-# INLINABLE cursorBackward #-}
cursorBackward :: Int -> Builder ()
cursorBackward Int
n = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'D')
{-# INLINABLE cursorDownLine #-}
cursorDownLine :: Int -> Builder ()
cursorDownLine Int
n = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'E')
{-# INLINABLE cursorUpLine #-}
cursorUpLine :: Int -> Builder ()
cursorUpLine Int
n   = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'F')

getCursorPosition :: BufferedInput -> IO (Int, Int)
{-# INLINABLE getCursorPosition #-}
getCursorPosition :: BufferedInput -> IO (Int, Int)
getCursorPosition BufferedInput
i = do
    BufferedInput -> IO ()
clearInputBuffer BufferedInput
i
    Builder () -> IO ()
forall a. HasCallStack => Builder a -> IO ()
putStd ([Int] -> Builder () -> Builder ()
csi [] Builder ()
"6n")
    Parser (Int, Int) -> BufferedInput -> IO (Int, Int)
forall a. HasCallStack => Parser a -> BufferedInput -> IO a
readParser (do
        Word8 -> Parser ()
P.word8 Word8
ESC
        Word8 -> Parser ()
P.word8 Word8
BRACKET_LEFT
        !Int
n <- Parser Int
forall a. (Integral a, Bounded a) => Parser a
P.int
        Word8 -> Parser ()
P.word8 Word8
SEMICOLON
        !Int
m <- Parser Int
forall a. (Integral a, Bounded a) => Parser a
P.int
        Word8 -> Parser ()
P.word8 Word8
LETTER_R
        (Int, Int) -> Parser (Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
m, Int
n)) BufferedInput
i

-- | Code to move the cursor to the specified column. The column numbering is
-- 1-based (that is, the left-most column is numbered 1).
setCursorColumn :: Int -- ^ 1-based column to move to
                -> B.Builder ()
{-# INLINABLE setCursorColumn #-}
setCursorColumn :: Int -> Builder ()
setCursorColumn Int
n = [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'G')

-- | Code to move the cursor to the specified position (row and column). The
-- position is 1-based (that is, the top-left corner is at row 1 column 1).
setCursorPosition :: Int -- ^ 1-based row to move to
                  -> Int -- ^ 1-based column to move to
                  -> B.Builder ()
{-# INLINABLE setCursorPosition #-}
setCursorPosition :: Int -> Int -> Builder ()
setCursorPosition Int
n Int
m = [Int] -> Builder () -> Builder ()
csi [Int
n, Int
m] (Char -> Builder ()
B.char8 Char
'G')

saveCursor, restoreCursor :: B.Builder ()
{-# INLINABLE saveCursor #-}
saveCursor :: Builder ()
saveCursor    = Char -> Builder ()
B.char8 Char
'\ESC' Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> Builder ()
B.char8 Char
'7'
{-# INLINABLE restoreCursor #-}
restoreCursor :: Builder ()
restoreCursor = Char -> Builder ()
B.char8 Char
'\ESC' Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> Builder ()
B.char8 Char
'8'

clearFromCursorToScreenEnd, clearFromCursorToScreenBeginning, clearScreen :: B.Builder ()
clearFromCursorToLineEnd, clearFromCursorToLineBeginning, clearLine :: B.Builder ()

{-# INLINABLE clearFromCursorToScreenEnd #-}
clearFromCursorToScreenEnd :: Builder ()
clearFromCursorToScreenEnd       = [Int] -> Builder () -> Builder ()
csi [Int
0] (Char -> Builder ()
B.char8 Char
'J')
{-# INLINABLE clearFromCursorToScreenBeginning #-}
clearFromCursorToScreenBeginning :: Builder ()
clearFromCursorToScreenBeginning = [Int] -> Builder () -> Builder ()
csi [Int
1] (Char -> Builder ()
B.char8 Char
'J')
{-# INLINABLE clearScreen #-}
clearScreen :: Builder ()
clearScreen                      = [Int] -> Builder () -> Builder ()
csi [Int
2] (Char -> Builder ()
B.char8 Char
'J')
{-# INLINABLE clearFromCursorToLineEnd #-}
clearFromCursorToLineEnd :: Builder ()
clearFromCursorToLineEnd         = [Int] -> Builder () -> Builder ()
csi [Int
0] (Char -> Builder ()
B.char8 Char
'K')
{-# INLINABLE clearFromCursorToLineBeginning #-}
clearFromCursorToLineBeginning :: Builder ()
clearFromCursorToLineBeginning   = [Int] -> Builder () -> Builder ()
csi [Int
1] (Char -> Builder ()
B.char8 Char
'K')
{-# INLINABLE clearLine #-}
clearLine :: Builder ()
clearLine                        = [Int] -> Builder () -> Builder ()
csi [Int
2] (Char -> Builder ()
B.char8 Char
'K')

scrollPageUp, scrollPageDown :: Int -- ^ Number of lines to scroll by
                             -> B.Builder()
{-# INLINABLE scrollPageUp #-}
scrollPageUp :: Int -> Builder ()
scrollPageUp Int
n   = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'S')
{-# INLINABLE scrollPageDown #-}
scrollPageDown :: Int -> Builder ()
scrollPageDown Int
n = Bool -> Builder () -> Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Builder () -> Builder ()) -> Builder () -> Builder ()
forall a b. (a -> b) -> a -> b
$ [Int] -> Builder () -> Builder ()
csi [Int
n] (Char -> Builder ()
B.char8 Char
'T')

hideCursor, showCursor :: B.Builder ()
{-# INLINABLE hideCursor #-}
hideCursor :: Builder ()
hideCursor = [Int] -> Builder () -> Builder ()
csi [] Builder ()
"?25l"
{-# INLINABLE showCursor #-}
showCursor :: Builder ()
showCursor = [Int] -> Builder () -> Builder ()
csi [] Builder ()
"?25h"

-- | XTerm control sequence to set the Icon Name and Window Title.
setTitle :: T.Text  -- ^ New Icon Name and Window Title
         -> B.Builder ()
{-# INLINABLE setTitle #-}
setTitle :: Text -> Builder ()
setTitle Text
title = do
    Builder ()
"\ESC]0;"
    Text -> Builder ()
B.text ((Char -> Bool) -> Text -> Text
T.filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\007') Text
title)
    Char -> Builder ()
B.char8 Char
'\007'

sgr :: [Word8]  -- ^ List of sgr code for the control sequence
    -> B.Builder ()
{-# INLINABLE sgr #-}
sgr :: [Word8] -> Builder ()
sgr [Word8]
args = do
    Char -> Builder ()
B.char8 Char
'\ESC'
    Char -> Builder ()
B.char8 Char
'['
    Builder () -> (Word8 -> Builder ()) -> [Word8] -> Builder ()
forall a. Builder () -> (a -> Builder ()) -> [a] -> Builder ()
B.intercalateList (Char -> Builder ()
B.char8 Char
';') Word8 -> Builder ()
forall a. (Integral a, Bounded a) => a -> Builder ()
B.int [Word8]
args
    Char -> Builder ()
B.char8 Char
'm'

reset :: B.Builder ()
{-# INLINABLE reset #-}
reset :: Builder ()
reset = [Word8] -> Builder ()
sgr [Word8
0]

boldIntensity, faintIntensity, resetIntensity :: B.Builder ()
{-# INLINABLE boldIntensity #-}
boldIntensity :: Builder ()
boldIntensity  = [Word8] -> Builder ()
sgr [Word8
1]
{-# INLINABLE faintIntensity #-}
faintIntensity :: Builder ()
faintIntensity = [Word8] -> Builder ()
sgr [Word8
2]
{-# INLINABLE resetIntensity #-}
resetIntensity :: Builder ()
resetIntensity    = [Word8] -> Builder ()
sgr [Word8
22]

bold :: B.Builder () -> B.Builder ()
{-# INLINABLE bold #-}
bold :: Builder () -> Builder ()
bold Builder ()
t = Builder ()
boldIntensity Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
t Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
resetIntensity

italicized, noItalicized :: B.Builder ()
{-# INLINABLE italicized #-}
italicized :: Builder ()
italicized      = [Word8] -> Builder ()
sgr [Word8
3]
{-# INLINABLE noItalicized #-}
noItalicized :: Builder ()
noItalicized    = [Word8] -> Builder ()
sgr [Word8
23]

-- | Italicize some text
italicize :: B.Builder () -> B.Builder ()
{-# INLINABLE italicize #-}
italicize :: Builder () -> Builder ()
italicize Builder ()
t = Builder ()
italicized Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
t Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
noItalicized

singleUnderline, doubleUnderline, noUnderline :: B.Builder ()
{-# INLINABLE singleUnderline #-}
singleUnderline :: Builder ()
singleUnderline = [Word8] -> Builder ()
sgr [Word8
4]
{-# INLINABLE doubleUnderline #-}
doubleUnderline :: Builder ()
doubleUnderline = [Word8] -> Builder ()
sgr [Word8
21]
{-# INLINABLE noUnderline #-}
noUnderline :: Builder ()
noUnderline   = [Word8] -> Builder ()
sgr [Word8
24]

-- | Add single underline to some text
underline  :: B.Builder () -> B.Builder ()
{-# INLINABLE underline #-}
underline :: Builder () -> Builder ()
underline Builder ()
t = Builder ()
singleUnderline Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
t Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Builder ()
singleUnderline

slowBlink, rapidBlink, blinkOff :: B.Builder ()
-- | less than 150 per minute
{-# INLINABLE slowBlink #-}
slowBlink :: Builder ()
slowBlink   = [Word8] -> Builder ()
sgr [Word8
5]
-- | MS-DOS ANSI.SYS, 150+ per minute; not widely supported
{-# INLINABLE rapidBlink #-}
rapidBlink :: Builder ()
rapidBlink  = [Word8] -> Builder ()
sgr [Word8
6]
{-# INLINABLE blinkOff #-}
blinkOff :: Builder ()
blinkOff     = [Word8] -> Builder ()
sgr [Word8
25]

conceal, reveal :: B.Builder ()
-- | Aka Hide, not widely supported.
{-# INLINABLE conceal #-}
conceal :: Builder ()
conceal = [Word8] -> Builder ()
sgr [Word8
8]
{-# INLINABLE reveal #-}
reveal :: Builder ()
reveal = [Word8] -> Builder ()
sgr [Word8
28]

invert, invertOff :: B.Builder ()
-- | Swap foreground and background colors, inconsistent emulation
{-# INLINABLE invert #-}
invert :: Builder ()
invert = [Word8] -> Builder ()
sgr [Word8
7]
{-# INLINABLE invertOff #-}
invertOff :: Builder ()
invertOff = [Word8] -> Builder ()
sgr [Word8
27]

-- | Colorized some text
color :: AnsiColor -> B.Builder () -> B.Builder ()
{-# INLINABLE color #-}
color :: AnsiColor -> Builder () -> Builder ()
color AnsiColor
c Builder ()
t = do
    AnsiColor -> Builder ()
setForeground AnsiColor
c
    Builder ()
t
    Builder ()
setDefaultForeground

-- | Colorized some text with background color
color' :: AnsiColor -> AnsiColor -> B.Builder () -> B.Builder ()
{-# INLINABLE color' #-}
color' :: AnsiColor -> AnsiColor -> Builder () -> Builder ()
color' AnsiColor
c1 AnsiColor
c2 Builder ()
t = do
    AnsiColor -> Builder ()
setForeground AnsiColor
c1
    AnsiColor -> Builder ()
setBackground AnsiColor
c2
    Builder ()
t
    Builder ()
setDefaultForeground
    Builder ()
setDefaultBackground

-- | Colorized some text
palette :: PaletteColor -> B.Builder () -> B.Builder ()
{-# INLINABLE palette #-}
palette :: Word8 -> Builder () -> Builder ()
palette Word8
c Builder ()
t = do
    Word8 -> Builder ()
setPaletteForeground Word8
c
    Builder ()
t
    Builder ()
setDefaultForeground

-- | Colorized some text with background color
palette' :: PaletteColor -> PaletteColor -> B.Builder () -> B.Builder ()
{-# INLINABLE palette' #-}
palette' :: Word8 -> Word8 -> Builder () -> Builder ()
palette' Word8
c1 Word8
c2 Builder ()
t = do
    Word8 -> Builder ()
setPaletteForeground Word8
c1
    Word8 -> Builder ()
setPaletteBackground Word8
c2
    Builder ()
t
    Builder ()
setDefaultForeground
    Builder ()
setDefaultBackground

-- | Colorized some text
rgb :: RGBColor -> B.Builder () -> B.Builder ()
{-# INLINABLE rgb #-}
rgb :: RGBColor -> Builder () -> Builder ()
rgb RGBColor
c Builder ()
t = do
    RGBColor -> Builder ()
setRGBForeground RGBColor
c
    Builder ()
t
    Builder ()
setDefaultForeground

-- | Colorized some text with background color
rgb' :: RGBColor -> RGBColor -> B.Builder () -> B.Builder ()
{-# INLINABLE rgb' #-}
rgb' :: RGBColor -> RGBColor -> Builder () -> Builder ()
rgb' RGBColor
c1 RGBColor
c2 Builder ()
t = do
    RGBColor -> Builder ()
setRGBForeground RGBColor
c1
    RGBColor -> Builder ()
setRGBBackground RGBColor
c2
    Builder ()
t
    Builder ()
setDefaultForeground
    Builder ()
setDefaultBackground

setForeground, setBrightForeground, setBackground, setBrightBackground :: AnsiColor -> B.Builder ()
{-# INLINABLE setForeground #-}
setForeground :: AnsiColor -> Builder ()
setForeground AnsiColor
c       = [Word8] -> Builder ()
sgr [Word8
30 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ AnsiColor -> Word8
colorToCode AnsiColor
c]
{-# INLINABLE setBrightForeground #-}
setBrightForeground :: AnsiColor -> Builder ()
setBrightForeground AnsiColor
c = [Word8] -> Builder ()
sgr [Word8
90 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ AnsiColor -> Word8
colorToCode AnsiColor
c]
{-# INLINABLE setBackground #-}
setBackground :: AnsiColor -> Builder ()
setBackground AnsiColor
c       = [Word8] -> Builder ()
sgr [Word8
40 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ AnsiColor -> Word8
colorToCode AnsiColor
c]
{-# INLINABLE setBrightBackground #-}
setBrightBackground :: AnsiColor -> Builder ()
setBrightBackground AnsiColor
c = [Word8] -> Builder ()
sgr [Word8
100 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ AnsiColor -> Word8
colorToCode AnsiColor
c]

setPaletteForeground, setPaletteBackground :: PaletteColor -> B.Builder ()
{-# INLINABLE setPaletteForeground #-}
setPaletteForeground :: Word8 -> Builder ()
setPaletteForeground Word8
index = [Word8] -> Builder ()
sgr [Word8
38, Word8
5, Word8
index]
{-# INLINABLE setPaletteBackground #-}
setPaletteBackground :: Word8 -> Builder ()
setPaletteBackground Word8
index = [Word8] -> Builder ()
sgr [Word8
48, Word8
5, Word8
index]

setRGBForeground, setRGBBackground :: RGBColor -> B.Builder ()
{-# INLINABLE setRGBForeground #-}
setRGBForeground :: RGBColor -> Builder ()
setRGBForeground (Word8
r,Word8
g,Word8
b) = [Word8] -> Builder ()
sgr [Word8
38, Word8
2, Word8
r, Word8
g, Word8
b]
{-# INLINABLE setRGBBackground #-}
setRGBBackground :: RGBColor -> Builder ()
setRGBBackground (Word8
r,Word8
g,Word8
b) = [Word8] -> Builder ()
sgr [Word8
48, Word8
2, Word8
r, Word8
g, Word8
b]

setDefaultForeground, setDefaultBackground :: B.Builder ()
{-# INLINABLE setDefaultForeground #-}
setDefaultForeground :: Builder ()
setDefaultForeground = [Word8] -> Builder ()
sgr [Word8
39]
{-# INLINABLE setDefaultBackground #-}
setDefaultBackground :: Builder ()
setDefaultBackground = [Word8] -> Builder ()
sgr [Word8
49]

-- | ANSI's eight standard colors
data AnsiColor = Black
               | Red
               | Green
               | Yellow
               | Blue
               | Magenta
               | Cyan
               | White
        deriving (AnsiColor -> AnsiColor -> Bool
(AnsiColor -> AnsiColor -> Bool)
-> (AnsiColor -> AnsiColor -> Bool) -> Eq AnsiColor
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AnsiColor -> AnsiColor -> Bool
$c/= :: AnsiColor -> AnsiColor -> Bool
== :: AnsiColor -> AnsiColor -> Bool
$c== :: AnsiColor -> AnsiColor -> Bool
Eq, Eq AnsiColor
Eq AnsiColor
-> (AnsiColor -> AnsiColor -> Ordering)
-> (AnsiColor -> AnsiColor -> Bool)
-> (AnsiColor -> AnsiColor -> Bool)
-> (AnsiColor -> AnsiColor -> Bool)
-> (AnsiColor -> AnsiColor -> Bool)
-> (AnsiColor -> AnsiColor -> AnsiColor)
-> (AnsiColor -> AnsiColor -> AnsiColor)
-> Ord AnsiColor
AnsiColor -> AnsiColor -> Bool
AnsiColor -> AnsiColor -> Ordering
AnsiColor -> AnsiColor -> AnsiColor
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AnsiColor -> AnsiColor -> AnsiColor
$cmin :: AnsiColor -> AnsiColor -> AnsiColor
max :: AnsiColor -> AnsiColor -> AnsiColor
$cmax :: AnsiColor -> AnsiColor -> AnsiColor
>= :: AnsiColor -> AnsiColor -> Bool
$c>= :: AnsiColor -> AnsiColor -> Bool
> :: AnsiColor -> AnsiColor -> Bool
$c> :: AnsiColor -> AnsiColor -> Bool
<= :: AnsiColor -> AnsiColor -> Bool
$c<= :: AnsiColor -> AnsiColor -> Bool
< :: AnsiColor -> AnsiColor -> Bool
$c< :: AnsiColor -> AnsiColor -> Bool
compare :: AnsiColor -> AnsiColor -> Ordering
$ccompare :: AnsiColor -> AnsiColor -> Ordering
$cp1Ord :: Eq AnsiColor
Ord, AnsiColor
AnsiColor -> AnsiColor -> Bounded AnsiColor
forall a. a -> a -> Bounded a
maxBound :: AnsiColor
$cmaxBound :: AnsiColor
minBound :: AnsiColor
$cminBound :: AnsiColor
Bounded, Int -> AnsiColor
AnsiColor -> Int
AnsiColor -> [AnsiColor]
AnsiColor -> AnsiColor
AnsiColor -> AnsiColor -> [AnsiColor]
AnsiColor -> AnsiColor -> AnsiColor -> [AnsiColor]
(AnsiColor -> AnsiColor)
-> (AnsiColor -> AnsiColor)
-> (Int -> AnsiColor)
-> (AnsiColor -> Int)
-> (AnsiColor -> [AnsiColor])
-> (AnsiColor -> AnsiColor -> [AnsiColor])
-> (AnsiColor -> AnsiColor -> [AnsiColor])
-> (AnsiColor -> AnsiColor -> AnsiColor -> [AnsiColor])
-> Enum AnsiColor
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: AnsiColor -> AnsiColor -> AnsiColor -> [AnsiColor]
$cenumFromThenTo :: AnsiColor -> AnsiColor -> AnsiColor -> [AnsiColor]
enumFromTo :: AnsiColor -> AnsiColor -> [AnsiColor]
$cenumFromTo :: AnsiColor -> AnsiColor -> [AnsiColor]
enumFromThen :: AnsiColor -> AnsiColor -> [AnsiColor]
$cenumFromThen :: AnsiColor -> AnsiColor -> [AnsiColor]
enumFrom :: AnsiColor -> [AnsiColor]
$cenumFrom :: AnsiColor -> [AnsiColor]
fromEnum :: AnsiColor -> Int
$cfromEnum :: AnsiColor -> Int
toEnum :: Int -> AnsiColor
$ctoEnum :: Int -> AnsiColor
pred :: AnsiColor -> AnsiColor
$cpred :: AnsiColor -> AnsiColor
succ :: AnsiColor -> AnsiColor
$csucc :: AnsiColor -> AnsiColor
Enum, Int -> AnsiColor -> ShowS
[AnsiColor] -> ShowS
AnsiColor -> String
(Int -> AnsiColor -> ShowS)
-> (AnsiColor -> String)
-> ([AnsiColor] -> ShowS)
-> Show AnsiColor
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AnsiColor] -> ShowS
$cshowList :: [AnsiColor] -> ShowS
show :: AnsiColor -> String
$cshow :: AnsiColor -> String
showsPrec :: Int -> AnsiColor -> ShowS
$cshowsPrec :: Int -> AnsiColor -> ShowS
Show, ReadPrec [AnsiColor]
ReadPrec AnsiColor
Int -> ReadS AnsiColor
ReadS [AnsiColor]
(Int -> ReadS AnsiColor)
-> ReadS [AnsiColor]
-> ReadPrec AnsiColor
-> ReadPrec [AnsiColor]
-> Read AnsiColor
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [AnsiColor]
$creadListPrec :: ReadPrec [AnsiColor]
readPrec :: ReadPrec AnsiColor
$creadPrec :: ReadPrec AnsiColor
readList :: ReadS [AnsiColor]
$creadList :: ReadS [AnsiColor]
readsPrec :: Int -> ReadS AnsiColor
$creadsPrec :: Int -> ReadS AnsiColor
Read, (forall x. AnsiColor -> Rep AnsiColor x)
-> (forall x. Rep AnsiColor x -> AnsiColor) -> Generic AnsiColor
forall x. Rep AnsiColor x -> AnsiColor
forall x. AnsiColor -> Rep AnsiColor x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AnsiColor x -> AnsiColor
$cfrom :: forall x. AnsiColor -> Rep AnsiColor x
Generic)
        deriving anyclass Int -> AnsiColor -> Builder ()
(Int -> AnsiColor -> Builder ()) -> Print AnsiColor
forall a. (Int -> a -> Builder ()) -> Print a
toUTF8BuilderP :: Int -> AnsiColor -> Builder ()
$ctoUTF8BuilderP :: Int -> AnsiColor -> Builder ()
T.Print

colorToCode :: AnsiColor -> Word8
{-# INLINABLE colorToCode #-}
colorToCode :: AnsiColor -> Word8
colorToCode AnsiColor
c = case AnsiColor
c of
    AnsiColor
Black   -> Word8
0
    AnsiColor
Red     -> Word8
1
    AnsiColor
Green   -> Word8
2
    AnsiColor
Yellow  -> Word8
3
    AnsiColor
Blue    -> Word8
4
    AnsiColor
Magenta -> Word8
5
    AnsiColor
Cyan    -> Word8
6
    AnsiColor
White   -> Word8
7

-- | 8-bit palette color, see https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
type PaletteColor = Word8

-- | 24-bit RGB color
type RGBColor = (Word8, Word8, Word8)