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
type flag =
| Bold
| Dim
| Italic
| Underline
| Double_underline
| Blink
| Inverse
| Hidden
| Strikethrough
| Overline
| Framed
| Encircled
let all_flags =
[|
Bold;
Dim;
Italic;
Underline;
Blink;
Inverse;
Hidden;
Strikethrough;
Double_underline;
Overline;
Framed;
Encircled;
|]
let bit = function
| Bold -> 0
| Dim -> 1
| Italic -> 2
| Underline -> 3
| Blink -> 4
| Inverse -> 5
| Hidden -> 6
| Strikethrough -> 7
| Double_underline -> 8
| Overline -> 9
| Framed -> 10
| Encircled -> 11
let flag_mask flag = 1 lsl bit flag
let flag_to_sgr_code = function
| Bold -> 1
| Dim -> 2
| Italic -> 3
| Underline -> 4
| Double_underline -> 21
| Blink -> 5
| Inverse -> 7
| Hidden -> 8
| Strikethrough -> 9
| Overline -> 53
| Framed -> 51
| Encircled -> 52
let flag_to_sgr_disable_code = function
| Bold -> 22
| Dim -> 22
| Italic -> 23
| Underline -> 24
| Double_underline -> 24
| Blink -> 25
| Inverse -> 27
| Hidden -> 28
| Strikethrough -> 29
| Overline -> 55
| Framed -> 54
| Encircled -> 54
let flag_to_string = function
| Bold -> "Bold"
| Dim -> "Dim"
| Italic -> "Italic"
| Underline -> "Underline"
| Double_underline -> "Double_underline"
| Blink -> "Blink"
| Inverse -> "Inverse"
| Hidden -> "Hidden"
| Strikethrough -> "Strikethrough"
| Overline -> "Overline"
| Framed -> "Framed"
| Encircled -> "Encircled"
type t = int
let empty = 0
let bold = flag_mask Bold
let dim = flag_mask Dim
let italic = flag_mask Italic
let underline = flag_mask Underline
let double_underline = flag_mask Double_underline
let blink = flag_mask Blink
let inverse = flag_mask Inverse
let hidden = flag_mask Hidden
let strikethrough = flag_mask Strikethrough
let overline = flag_mask Overline
let framed = flag_mask Framed
let encircled = flag_mask Encircled
let is_empty m = m = 0
let mem flag m = m land flag_mask flag <> 0
let add flag m = m lor flag_mask flag
let remove flag m = m land lnot (flag_mask flag)
let toggle flag m = m lxor flag_mask flag
let union a b = a lor b
let intersect a b = a land b
let diff a b = a land lnot b
let of_list flags = List.fold_left (fun acc flag -> add flag acc) empty flags
let to_list mask =
Array.fold_right
(fun flag acc -> if mem flag mask then flag :: acc else acc)
all_flags []
let cardinal mask =
let rec count n c = if n = 0 then c else count (n lsr 1) (c + (n land 1)) in
count mask 0
let combine ?(bold = false) ?(dim = false) ?(italic = false)
?(underline = false) ?(double_underline = false) ?(blink = false)
?(inverse = false) ?(hidden = false) ?(strikethrough = false)
?(overline = false) ?(framed = false) ?(encircled = false) () =
let set cond flag acc = if cond then add flag acc else acc in
empty |> set bold Bold |> set dim Dim |> set italic Italic
|> set underline Underline
|> set double_underline Double_underline
|> set blink Blink |> set inverse Inverse |> set hidden Hidden
|> set strikethrough Strikethrough
|> set overline Overline |> set framed Framed |> set encircled Encircled
let to_sgr_codes mask =
Array.fold_right
(fun flag acc ->
if mem flag mask then flag_to_sgr_code flag :: acc else acc)
all_flags []
let iter_sgr_codes f mask =
Array.iter
(fun flag -> if mem flag mask then f (flag_to_sgr_code flag))
all_flags
let iter_sgr_disable_codes f mask =
if mask land (bold lor dim) <> 0 then f 22;
if mask land italic <> 0 then f 23;
if mask land (underline lor double_underline) <> 0 then f 24;
if mask land blink <> 0 then f 25;
if mask land inverse <> 0 then f 27;
if mask land hidden <> 0 then f 28;
if mask land strikethrough <> 0 then f 29;
if mask land (framed lor encircled) <> 0 then f 54;
if mask land overline <> 0 then f 55
let fold_sgr_codes f mask init =
Array.fold_left
(fun acc flag ->
if mem flag mask then f (flag_to_sgr_code flag) acc else acc)
init all_flags
let pp fmt mask =
Format.pp_print_char fmt '[';
let (_ : bool) =
Array.fold_left
(fun first flag ->
if mem flag mask then begin
if not first then Format.fprintf fmt ",@ ";
Format.pp_print_string fmt (flag_to_string flag);
false
end
else first)
true all_flags
in
Format.pp_print_char fmt ']'
let pack mask = mask
let unpack mask = mask land 0xFFF
let fold f mask init =
Array.fold_left
(fun acc flag -> if mem flag mask then f flag acc else acc)
init all_flags
let iter f mask = fold (fun flag () -> f flag) mask ()
let with_flag flag enabled mask =
if enabled then add flag mask else remove flag mask
let equal a b = Int.equal a b
let compare a b = Int.compare a b