Code Snippet
src/Data/ANSI/EscapeCode.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
{-# LANGUAGE Safe #-}
--------------------------------------------------------------------------------
module Data.ANSI.EscapeCode
( Colour
( Black
, Red
, Green
, Yellow
, Blue
, Magenta
, Cyan
, White
)
, Frecuency
( Slow
, Fast
)
--
, sgr
--
, foreground
, background
, bold
, faint
, italic
, underline
, blink
) where
--------------------------------------------------------------------------------
data Colour
= Black
| Red
| Green
| Yellow
| Blue
| Magenta
| Cyan
| White
deriving ( Eq )
instance Enum Colour where
fromEnum Black = 0
fromEnum Red = 1
fromEnum Green = 2
fromEnum Yellow = 3
fromEnum Blue = 4
fromEnum Magenta = 5
fromEnum Cyan = 6
fromEnum White = 7
toEnum 0 = Black
toEnum 1 = Red
toEnum 2 = Green
toEnum 3 = Yellow
toEnum 4 = Blue
toEnum 5 = Magenta
toEnum 6 = Cyan
toEnum 7 = White
toEnum _ = error "Colour code not supported"
succ Black = Red
succ Red = Green
succ Green = Yellow
succ Yellow = Blue
succ Blue = Magenta
succ Magenta = Cyan
succ Cyan = White
succ White = Black
pred Black = White
pred Red = Black
pred Green = Red
pred Yellow = Green
pred Blue = Yellow
pred Magenta = Blue
pred Cyan = Magenta
pred White = Cyan
type Bright = Bool
data Background = BG ! Bool Bright Colour
data Foreground = FG ! Bool Bright Colour
data Frecuency
= Slow
| Fast
data Blink = B ! Bool Frecuency
data SelectGraphicRendition
= SGR ! Background ! Foreground ! Bool ! Bool ! Bool ! Bool ! Blink String
instance Show SelectGraphicRendition where
show ( SGR bg fg bo fa it un bl text ) =
" \ESC [" ++
"0" ++
( cb bg ) ++
( cf fg ) ++
( fb bo ) ++
( ff fa ) ++
( fi it ) ++
( fu un ) ++
( bf bl ) ++
"m" ++
text ++
" \ESC [00m"
where
cb ( BG True True c ) = ";" ++ ( show $ 60 + 40 + fromEnum c )
cb ( BG True False c ) = ";" ++ ( show $ 40 + fromEnum c )
cb ( BG False _____ _ ) = [ ]
cf ( FG True True c ) = ";" ++ ( show $ 60 + 30 + fromEnum c )
cf ( FG True False c ) = ";" ++ ( show $ 30 + fromEnum c )
cf ( FG False _____ _ ) = [ ]
fb True = ";01"
fb False = [ ]
ff True = ";02"
ff False = [ ]
fi True = ";03"
fi False = [ ]
fu True = ";04"
fu False = [ ]
bf ( B True Slow ) = ";05"
bf ( B True Fast ) = ";06"
bf ( B False ____ ) = [ ]
--------------------------------------------------------------------------------
sgr
:: String
-> SelectGraphicRendition
foreground
:: Bright
-> Colour
-> SelectGraphicRendition
-> SelectGraphicRendition
background
:: Bright
-> Colour
-> SelectGraphicRendition
-> SelectGraphicRendition
bold
:: SelectGraphicRendition
-> SelectGraphicRendition
faint
:: SelectGraphicRendition
-> SelectGraphicRendition
italic
:: SelectGraphicRendition
-> SelectGraphicRendition
underline
:: SelectGraphicRendition
-> SelectGraphicRendition
blink
:: Frecuency
-> SelectGraphicRendition
-> SelectGraphicRendition
--------------------------------------------------------------------------------
sgr =
SGR bg fg bo fa it un bl
where
fg = FG False undefined undefined
bg = BG False undefined undefined
bo = False
fa = False
it = False
un = False
bl = B False undefined
--------------------------------------------------------------------------------
foreground b c ( SGR bg __ bo fa it un bl txt ) =
SGR bg fg bo fa it un bl txt
where
fg = FG True b c
background b c ( SGR __ fg bo fa it un bl txt ) =
SGR bg fg bo fa it un bl txt
where
bg = BG True b c
bold ( SGR bg fg __ fa it un bl txt ) =
SGR bg fg bo fa it un bl txt
where
bo = True
faint ( SGR bg fg bo __ it un bl txt ) =
SGR bg fg bo fa it un bl txt
where
fa = True
italic ( SGR bg fg bo fa __ un bl txt ) =
SGR bg fg bo fa it un bl txt
where
it = True
underline ( SGR bg fg bo fa it __ bl txt ) =
SGR bg fg bo fa it un bl txt
where
un = True
blink f ( SGR bg fg bo fa it un __ txt ) =
SGR bg fg bo fa it un bl txt
where
bl = B True f
--------------------------------------------------------------------------------
-- References
--
-- ANSI escape code:
-- * https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
src/Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/ usr / bin / env stack
{- stack
--resolver lts-13.30
--install-ghc
script
--ghc-options -Werror
--ghc-options -Wall
--
-}
--------------------------------------------------------------------------------
module Main ( main ) where
--------------------------------------------------------------------------------
import Data.Word
( Word8
)
import Data.ANSI.EscapeCode
( Colour ( Black , Blue , Green , Red , Yellow )
, Frecuency ( Fast )
, background
, blink
, bold
, faint
, foreground
, italic
, sgr
, underline
)
--------------------------------------------------------------------------------
codes :: [ String ]
codes =
map f [ 0 .. 107 ]
where
f :: Word8 -> String
f n = " \ESC [" ++ show n ++ "m " ++ g n ++ " \ESC [m"
g n = leftpad 3 ( Just ' ' ) $ show n
main :: IO ()
main =
( putStrLn "# As in the `Example of use in C`:" ) >>
( mapM_ ( putStrLn . concat ) $ chunksOf 10 $ codes ) >>
( putStrLn "" ) >>
( putStrLn "# Using the Data.ANSI.EscapeCode module:" ) >>
( putStrLn . show . f $ t ) >>
( putStrLn . show . g $ t ) >>
( putStrLn . show . h $ t )
where
f = bold . blink Fast . foreground True Yellow . background False Red . sgr
g = underline . foreground False Black . background True Green . sgr
h = faint . italic . foreground False Black . background True Blue . sgr
t = "this is just some text"
--------------------------------------------------------------------------------
-- HELPERS
leftpad :: Int -> Maybe Char -> String -> String
leftpad n m x =
if l > n
then x
else replicate ( n - l ) c ++ x
where
l = length x
c =
case m of
Just v -> v
Nothing -> '.'
chunksOf :: Int -> [ a ] -> [[ a ]]
chunksOf _ [] = [ ]
chunksOf n bs = x : chunksOf n xs
where
( x , xs ) = splitAt n bs
--------------------------------------------------------------------------------
-- References
--
-- ANSI escape code:
-- * https://en.wikipedia.org/wiki/ANSI_escape_code#Example_of_use_in_C
src/package.cabal
cabal-version: 1.12
name: package
version: 0.11.0.0
build-type: Simple
executable ansi-color
main-is:
Main.hs
other-modules:
Paths_package
Data.ANSI.EscapeCode
hs-source-dirs:
./.
ghc-options:
---------------------------------------------------------------------------
-- GHC 8.6.4 Users Guide > 9. Using GHC > 9.2. Warnings and sanity-checking
-- * Base: https://downloads.haskell.org/~ghc/8.6.4/docs/html/users_guide/
-- * File: using-warnings.html
-- Warnings that are not enabled by -Wall:
---------------------------------------------------------------------------
-Wall
-Wincomplete-record-updates
-- -Wmonomorphism-restriction
-- -Wimplicit-prelude
-- -Wmissing-local-signatures
-Wmissing-exported-signatures
-- -Wmissing-export-lists
-- -Wmissing-import-lists
-Wmissing-home-modules
-Widentities
-Wredundant-constraints
-- Added since GHC 8.4
-Wpartial-fields
-- -Wmissed-specialisations
-- -Wall-missed-specialisations
---------------------------------------------------------------------------
-- Added to allow instance definition in other files, in order to keep the
-- Effect module SAFE so it can be imported by the Process
---------------------------------------------------------------------------
-Wno-orphans
-- Makes any warning into a fatal error.
-Werror
---------------------------------------------------------------------------
-- Deterministic builds (Uniques):
-- * https://gitlab.haskell.org/ghc/ghc/wikis/deterministic-builds#progress
-- * https://www.youtube.com/watch?v=FNzTk4P4fL4 (08 GHC Determinism ICFP)
---------------------------------------------------------------------------
-dinitial-unique=0
-dunique-increment=1
---------------------------------------------------------------------------
-- The -N flag built-in can be modified on runtime based on the system
-- hosting the binary for optimal performance:
-- - https://hackage.haskell.org/package/base/docs/GHC-Conc.html
-- * getNumProcessors
-- - https://hackage.haskell.org/package/base/docs/Control-Concurrent.html
-- * setNumCapabilities
---------------------------------------------------------------------------
-- 12.40. Safe Haskell > ... > 12.40.1.1. Strict type-safety (good style)
-- * Enforce good style, similar to the function of -Wall.
-XSafe
-fpackage-trust
-trust=base
-- Only Trustworthy packages can be trusted
-- * Base: https://downloads.haskell.org/~ghc/8.6.4/docs/html/users_guide/
-- * File: safe_haskell.html
---------------------------------------------------------------------------
-O2
-threaded
-rtsopts
-with-rtsopts=-N
build-depends:
-- Prelude
base
default-language:
Haskell98
stack.yaml
resolver : lts-13.30
packages :
- src
nix :
enable : true
packages : []
path : [
" nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/6420e26.tar.gz"
]
## Reference
# Stack:
# - https://www.stackage.org/lts-13.30
# NixOS:
# - https://github.com/NixOS/nixpkgs-channels/branches/active
# - https://github.com/NixOS/nixpkgs-channels/tree/nixos-19.03
# - https://github.com/NixOS/nixpkgs-channels/tree/6420e26
# - https://github.com/NixOS/nixpkgs-channels/archive/6420e26.tar.gz
build.bash
#!/usr/bin/env bash
clear
src = " $( stack path --local-install-root ) /bin"
tgt = "./bin"
echo "### Clearing binary files:"
find $tgt -mindepth 1 -name "*" -delete -print
echo
echo "### Stack cleaning and building:"
stack build
echo
echo "### Copying binary to local $tgt :"
if [ ! -d $tgt ] ; then
mkdir -p $tgt ;
fi
cp -v $src /* $tgt /
echo
bin = $( ls $tgt ) # We need to ls after binaries are created
echo "### Repoducible hashes:"
for f in $bin ; do
echo -e $( sha256sum $tgt /$f | cut -d " " -f 1) : $f
done ;
echo
Code Output:
./build.bash && ./bin/ansi-color
### Clearing binary files:
./bin/ansi-color
### Stack cleaning and building:
### Copying binary to local ./bin:
'/home/johndoe/code/haskell/ansi-color/.stack-work/install/x86_64-linux-nix/e07ba7d58ca3cbf46d17cb550fd0dc7ccd1bfc735df47120e593b662560d5c08/8.6.5/bin/ansi-color' -> './bin/ansi-color'
### Repoducible hashes:
75843be327c60bb8f6c210111320a6370eb0997261a46d904d32db7f3b490bc7: ansi-color
ANSI > Escape Code > Select Graphic Rendition (blinking)
ANSI > Escape Code > Select Graphic Rendition (blinking)
References:
Wikipedia (ANSI escape code):