1#include "Common-Safe-Haskell.hs"
2
3{-| The \'ANSI\' standards refer to the visual style of displaying characters as
4their \'graphic rendition\'. The style includes the color of a character or its
5background, the intensity (bold, normal or faint) of a character, or whether the
6character is italic or underlined (single or double), blinking (slowly or
7rapidly) or visible or not. The \'ANSI\' codes to establish the graphic
8rendition for subsequent text are referred to as SELECT GRAPHIC RENDITION (SGR).
9
10This module exports types and functions used to represent SGR aspects. See also
11'System.Console.ANSI.setSGR' and related functions.
12-}
13module System.Console.ANSI.Types
14  (
15  -- * Types used to represent SGR aspects
16    SGR (..)
17  , ConsoleLayer (..)
18  , Color (..)
19  , ColorIntensity (..)
20  , ConsoleIntensity (..)
21  , Underlining (..)
22  , BlinkSpeed (..)
23  -- * Constructors of xterm 256-color palette indices
24  , xterm6LevelRGB
25  , xterm24LevelGray
26  , xtermSystem
27  ) where
28
29import Data.Ix (Ix)
30import Data.Word (Word8)
31
32import Data.Colour (Colour)
33
34-- | ANSI's eight standard colors. They come in two intensities, which are
35-- controlled by 'ColorIntensity'. Many terminals allow the colors of the
36-- standard palette to be customised, so that, for example,
37-- @setSGR [ SetColor Foreground Vivid Green ]@ may not result in bright green
38-- characters.
39data Color = Black
40           | Red
41           | Green
42           | Yellow
43           | Blue
44           | Magenta
45           | Cyan
46           | White
47           deriving (Eq, Ord, Bounded, Enum, Show, Read, Ix)
48
49-- | ANSI's standard colors come in two intensities
50data ColorIntensity = Dull
51                    | Vivid
52                    deriving (Eq, Ord, Bounded, Enum, Show, Read, Ix)
53
54-- | ANSI colors can be set on two different layers
55data ConsoleLayer = Foreground
56                  | Background
57                  deriving (Eq, Ord, Bounded, Enum, Show, Read, Ix)
58
59-- | ANSI blink speeds: values other than 'NoBlink' are not widely supported
60data BlinkSpeed = SlowBlink -- ^ Less than 150 blinks per minute
61                | RapidBlink -- ^ More than 150 blinks per minute
62                | NoBlink
63                deriving (Eq, Ord, Bounded, Enum, Show, Read, Ix)
64
65-- | ANSI text underlining
66data Underlining
67  = SingleUnderline
68  -- | Not widely supported. Not supported natively on Windows 10
69  | DoubleUnderline
70  | NoUnderline
71  deriving (Eq, Ord, Bounded ,Enum, Show, Read, Ix)
72
73-- | ANSI general console intensity: usually treated as setting the font style
74-- (e.g. 'BoldIntensity' causes text to be bold)
75data ConsoleIntensity
76  = BoldIntensity
77  -- | Not widely supported: sometimes treated as concealing text. Not supported
78  -- natively on Windows 10
79  | FaintIntensity
80  | NormalIntensity
81  deriving (Eq, Ord, Bounded, Enum, Show, Read, Ix)
82
83-- | ANSI Select Graphic Rendition (SGR) command
84--
85-- In respect of colors, there are three alternative commands:
86--
87-- (1) the \'ANSI\' standards allow for eight standard colors (with two
88-- intensities). Windows and many other terminals (including xterm) allow the
89-- user to redefine the standard colors (so, for example 'Vivid' 'Green' may not
90-- correspond to bright green;
91--
92-- (2) an extension of the standard that allows true colors (24 bit color depth)
93-- in RGB space. This is usually the best alternative for more colors; and
94--
95-- (3) another extension that allows a palette of 256 colors, each color
96-- specified by an index. Xterm provides a protocol for a palette of 256 colors
97-- that many other terminals, including Windows 10, follow. Some terminals
98-- (including xterm) allow the user to redefine some or all of the palette
99-- colors.
100data SGR
101  -- | Default rendition, cancels the effect of any preceding occurrence of SGR
102  -- (implementation-defined)
103  = Reset
104  -- | Set the character intensity. Partially supported natively on Windows 10
105  | SetConsoleIntensity !ConsoleIntensity
106  -- | Set italicized. Not widely supported: sometimes treated as swapping
107  -- foreground and background. Not supported natively on Windows 10
108  | SetItalicized !Bool
109  -- | Set or clear underlining. Partially supported natively on Windows 10
110  | SetUnderlining !Underlining
111  -- | Set or clear character blinking. Not supported natively on Windows 10
112  | SetBlinkSpeed !BlinkSpeed
113  -- | Set revealed or concealed. Not widely supported. Not supported natively
114  -- on Windows 10
115  | SetVisible !Bool
116  -- | Set negative or positive image. Supported natively on Windows 10
117  | SetSwapForegroundBackground !Bool
118  -- | Set a color from the standard palette of 16 colors (8 colors by 2
119  -- color intensities). Many terminals allow the palette colors to be
120  -- customised
121  | SetColor !ConsoleLayer !ColorIntensity !Color
122  -- | Set a true color (24 bit color depth). Supported natively on Windows 10
123  -- from the Creators Update (April 2017)
124  --
125  -- @since 0.7
126  | SetRGBColor !ConsoleLayer !(Colour Float)
127  -- | Set a color from a palette of 256 colors using a numerical index
128  -- (0-based). Supported natively on Windows 10 from the Creators Update (April
129  -- 2017) but not on legacy Windows native terminals. See 'xtermSystem',
130  -- 'xterm6LevelRGB' and 'xterm24LevelGray' to construct indices based on
131  -- xterm's standard protocol for a 256-color palette.
132  --
133  -- @since 0.9
134  | SetPaletteColor !ConsoleLayer !Word8
135  -- | Set a color to the default (implementation-defined)
136  --
137  -- @since 0.10
138  | SetDefaultColor !ConsoleLayer
139  deriving (Eq, Show, Read)
140
141-- | Given xterm's standard protocol for a 256-color palette, returns the index
142-- to that part of the palette which is a 6 level (6x6x6) color cube of 216 RGB
143-- colors. Throws an error if any of the red, green or blue channels is outside
144-- the range 0 to 5. An example of use is:
145--
146-- >>> setSGR [ SetPaletteColor $ xterm6LevelRGB 5 2 0 ] -- Dark Orange
147--
148-- @since 0.9
149xterm6LevelRGB :: Int -> Int -> Int -> Word8
150xterm6LevelRGB r g b
151  -- RGB colors are represented by index:
152  -- 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
153  | r >= 0 && r < 6 && g >= 0 && g < 6 && b >= 0 && b < 6
154  =  fromIntegral $ 16 + 36 * r + 6 * g + b
155  | otherwise
156  = error $ show r ++ " " ++ show g ++ " " ++ show b ++ " (r g b) is " ++
157            "outside of a 6 level (6x6x6) color cube."
158
159-- | Given xterm's standard protocol for a 256-color palette, returns the index
160-- to that part of the palette which is a spectrum of 24 grays, from dark
161-- gray (0) to near white (23) (black and white are themselves excluded). Throws
162-- an error if the gray is outside of the range 0 to 23. An example of use is:
163--
164-- >>> setSGR [ SetPaletteColor $ xterm24LevelGray 12 ] -- Gray50
165--
166-- @since 0.9
167xterm24LevelGray :: Int -> Word8
168xterm24LevelGray y
169  -- Grayscale colors are represented by index:
170  -- 232 + g (0 ≤ g ≤ 23)
171  | y >= 0 && y < 24 = fromIntegral $ 232 + y
172  | otherwise
173  = error $ show y ++ " (gray) is outside of the range 0 to 23."
174
175-- | Given xterm's standard protocol for a 256-color palette, returns the index
176-- to that part of the palette which corresponds to the \'ANSI\' standards' 16
177-- standard, or \'system\', colors (eight colors in two intensities). An example
178-- of use is:
179--
180-- >>> setSGR [ SetPaletteColor $ xtermSystem Vivid Green ]
181--
182-- @since 0.9
183xtermSystem :: ColorIntensity -> Color -> Word8
184xtermSystem intensity color
185  | intensity == Dull  = index
186  | otherwise          = index + 8
187 where
188  index = fromIntegral $ fromEnum color
189