Source file b0__fmt.ml
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
let stdout = Format.std_formatter
let stderr = Format.err_formatter
let pf = Format.fprintf
let pr = Format.printf
let epr = Format.eprintf
let str = Format.asprintf
let kpf = Format.kfprintf
let kstr = Format.kasprintf
let failwith_line n fmt = kstr failwith ("%d:" ^^ fmt) n
let failwith fmt = kstr failwith fmt
let failwith_notrace fmt = kstr (fun s -> raise_notrace (Failure s)) fmt
let invalid_arg fmt = kstr invalid_arg fmt
let error fmt = kstr (fun s -> Error s) fmt
type 'a t = Format.formatter -> 'a -> unit
let flush ppf _ = Format.pp_print_flush ppf ()
let flush_nl ppf _ = Format.pp_print_newline ppf ()
let nop ppf _ = ()
let any fmt ppf _ = pf ppf fmt
let using f pp_v ppf v = pp_v ppf (f v)
let raw_char = Format.pp_print_char
let raw_string = Format.pp_print_string
let box ?(indent = 0) pp_v ppf v =
Format.(pp_open_box ppf indent; pp_v ppf v; pp_close_box ppf ())
let hbox pp_v ppf v =
Format.(pp_open_hbox ppf (); pp_v ppf v; pp_close_box ppf ())
let vbox ?(indent = 0) pp_v ppf v =
Format.(pp_open_vbox ppf indent; pp_v ppf v; pp_close_box ppf ())
let hvbox ?(indent = 0) pp_v ppf v =
Format.(pp_open_hvbox ppf indent; pp_v ppf v; pp_close_box ppf ())
let hovbox ?(indent = 0) pp_v ppf v =
Format.(pp_open_hovbox ppf indent; pp_v ppf v; pp_close_box ppf ())
let cut ppf _ = Format.pp_print_cut ppf ()
let sp ppf _ = Format.pp_print_space ppf ()
let sps n ppf _ = Format.pp_print_break ppf n 0
let comma ppf _ = Format.pp_print_string ppf ","; sp ppf ()
let semi ppf _ = Format.pp_print_string ppf ";"; sp ppf ()
let suffix_lines ~suffix pp ppf v =
let b = Buffer.create 255 in
let () = box pp (Format.formatter_of_buffer b) v in
let lines = Buffer.contents b in
let lines = String.split_on_char '\n' lines in
let last = List.length lines - 1 in
let add_newline_esc i l = if i = last then l else l ^ suffix in
let lines = List.mapi add_newline_esc lines in
vbox (Format.pp_print_list raw_string) ppf lines
let iter ?sep:(pp_sep = cut) iter pp_elt ppf v =
let is_first = ref true in
let pp_elt v =
if !is_first then (is_first := false) else pp_sep ppf ();
pp_elt ppf v
in
iter pp_elt v
let iter_bindings ?sep:(pp_sep = cut) iter pp_binding ppf v =
let is_first = ref true in
let pp_binding k v =
if !is_first then (is_first := false) else pp_sep ppf ();
pp_binding ppf (k, v)
in
iter pp_binding v
let append pp_v0 pp_v1 ppf v = pp_v0 ppf v; pp_v1 ppf v
let ( ++ ) = append
let concat ?sep pps ppf v =
iter ?sep List.iter (fun ppf pp -> pp ppf v) ppf pps
let surround s1 s2 pp_v ppf v =
Format.(pp_print_string ppf s1; pp_v ppf v; pp_print_string ppf s2)
let parens pp_v = box ~indent:1 (surround "(" ")" pp_v)
let brackets pp_v = box ~indent:1 (surround "[" "]" pp_v)
let oxford_brackets pp_v = box ~indent:2 (surround "[|" "|]" pp_v)
let braces pp_v = box ~indent:1 (surround "{" "}" pp_v)
let quote ?(mark = "\"") pp_v =
let pp_mark ppf _ = Format.pp_print_as ppf 1 mark in
box ~indent:1 (pp_mark ++ pp_v ++ pp_mark)
let record ?(sep = cut) pps = vbox (concat ~sep pps)
let char = raw_char
let text = Format.pp_print_text
let styled_text ppf s =
let rec loop ppf s i max =
if i > max then () else
let ansi = s.[i] = '\x1B' && i + 1 < max && s.[i+1] = '[' in
if not ansi then match s.[i] with
| ' ' when i = max || s.[i+1] = ' ' || s.[i+1] = '\n' ->
loop ppf s (i + 1) max
| ' ' -> sp ppf (); loop ppf s (i + 1) max
| '\n' when i = max || s.[i+1] = ' ' -> loop ppf s (i + 1) max
| '\n' when s.[i+1] = '\n' ->
Format.pp_force_newline ppf ();
if i > 0 && s.[i-1] <> '\n' then Format.pp_force_newline ppf ();
loop ppf s (i + 1) max
| '\n' -> sp ppf (); loop ppf s (i + 1) max
| c -> char ppf s.[i]; loop ppf s (i + 1) max
else begin
let k = ref (i + 2) in
while (!k <= max && s.[!k] <> 'm') do incr k done;
let esc = String.sub s i (!k - i + 1) in
Format.pp_print_as ppf 0 esc;
loop ppf s (!k + 1) max
end
in
loop ppf s 0 (String.length s - 1)
let lines ppf s =
let rec stop_at sat ~start ~max s =
if start > max then start else
if sat s.[start] then start else
stop_at sat ~start:(start + 1) ~max s
in
let sub s start stop ~max =
if start = stop then "" else
if start = 0 && stop > max then s else
String.sub s start (stop - start)
in
let is_nl c = c = '\n' in
let max = String.length s - 1 in
let rec loop start s = match stop_at is_nl ~start ~max s with
| stop when stop > max -> Format.pp_print_string ppf (sub s start stop ~max)
| stop ->
Format.pp_print_string ppf (sub s start stop ~max);
Format.pp_force_newline ppf ();
loop (stop + 1) s
in
loop 0 s
let truncated ~max ppf s =
if String.length s <= max then raw_string ppf s else
(for i = 0 to max - 2 do raw_char ppf s.[i] done;
Format.pp_print_as ppf 1 "…")
let pp_hex_escaped_char ppf c = pf ppf "\\x%02x" (Char.code c)
let ascii_char ppf c =
if B0__char.Ascii.is_print c
then raw_char ppf c
else pp_hex_escaped_char ppf c
let _ascii_string ~for_literal ppf s =
let escape_char ~for_literal c =
(c = '\"' && for_literal) || not (B0__char.Ascii.is_print c)
in
let esc ~for_literal ppf c = match Char.code c with
| 0x22 when for_literal -> raw_char ppf '\\'; raw_char ppf '\"'
| 0x5C when for_literal -> raw_char ppf '\\'; raw_char ppf '\\'
| 0x0D when for_literal -> raw_char ppf '\\'; raw_char ppf 'r'
| 0x0A when for_literal -> raw_char ppf '\\'; raw_char ppf 'n'
| _ -> pp_hex_escaped_char ppf c
in
for i = 0 to String.length s - 1 do
let c = s.[i] in
if escape_char ~for_literal c then esc ~for_literal ppf c else
raw_char ppf c
done
let ascii_string ppf s = _ascii_string ~for_literal:false ppf s
let ascii_string_literal ppf s =
raw_char ppf '\"'; _ascii_string ~for_literal:true ppf s; raw_char ppf '\"'
let text_uchar ppf u =
let esc = match Uchar.to_int u with
| u when 0x0000 <= u && u <= 0x001F -> true
| u when 0x0080 <= u && u <= 0x009F -> true
| 0x2028 -> true
| 0x2029 -> true
| 0x200E -> true
| 0x200F -> true
| u -> false
in
if esc then pf ppf "U+%04X" (Uchar.to_int u) else
let b = Bytes.create (Uchar.utf_8_byte_length u) in
ignore (Bytes.set_utf_8_uchar b 0 u);
Format.pp_print_as ppf 1 (Bytes.unsafe_to_string b)
let _text_string ~ansi ~for_literal ppf s =
let escape_uchar ~for_literal u = match Uchar.to_int u with
| 0x0022 -> for_literal
| u when 0x0000 <= u && u <= 0x001F -> true
| u when 0x0080 <= u && u <= 0x009F -> true
| 0x2028 -> true
| 0x2029 -> true
| _ -> false
in
let escape ~for_literal ppf u = match Uchar.to_int u with
| 0x0022 when for_literal -> raw_char ppf '\\'; raw_char ppf '\"'
| 0x005C when for_literal -> raw_string ppf "\\\\"
| 0x000A when for_literal -> raw_string ppf "\\n"
| 0x000D when for_literal -> raw_string ppf "\\r"
| u -> pf ppf "\\u{%04X}" u
in
let rec loop ~for_literal ppf i max =
if i > max then () else
let dec = String.get_utf_8_uchar s i in
let u = Uchar.utf_decode_uchar dec in
let len = Uchar.utf_decode_length dec in
let next =
if ansi && Uchar.to_int u = 0x001B && i + 1 < max && s.[i + 1] = '['
then begin
let k = ref (i + 2) in
while (!k <= max && s.[!k] <> 'm') do incr k done;
let esc = String.sub s i (!k - i + 1) in
Format.pp_print_as ppf 0 esc;
!k + 1
end else begin
let () =
if escape_uchar ~for_literal u then escape ~for_literal ppf u else
if not (Uchar.utf_decode_is_valid dec) then raw_string ppf "\u{FFFD}"
else for k = 0 to len - 1 do raw_char ppf (s.[i + k]) done
in
i + len
end
in
loop ~for_literal ppf next max
in
loop ~for_literal ppf 0 (String.length s - 1)
let text_string ppf s = _text_string ~ansi:false ~for_literal:false ppf s
let text_bytes ppf b = text_string ppf (Bytes.unsafe_to_string b)
let string = raw_string
let text_string_literal ppf s =
raw_char ppf '\"';
_text_string ~ansi:false ~for_literal:true ppf s;
raw_char ppf '\"'
let styled_text_string ppf s =
_text_string ~ansi:true ~for_literal:false ppf s
let styled_text_string_literal ppf s =
raw_char ppf '\"';
_text_string ~ansi:true ~for_literal:true ppf s;
raw_char ppf '\"'
let bool = Format.pp_print_bool
let int = Format.pp_print_int
let int32 ppf i = pf ppf "%ld" i
let uint32 ppf i = pf ppf "%lu" i
let int64 ppf i = pf ppf "%Ld" i
let uint64 ppf i = pf ppf "%Lu" i
let nativeint ppf i = pf ppf "%nd" i
let nativeuint ppf i = pf ppf "%nu" i
let float ppf f = pf ppf "%g" f
let binary_string =
let pp_byte ppf c = pf ppf "%02x" (Char.code c) in
iter String.iter pp_byte
let bytes ppf v = binary_string ppf (Bytes.unsafe_to_string v)
let sys_signal ppf snum =
let sigs = [
Sys.sigabrt, "SIGABRT"; Sys.sigalrm, "SIGALRM"; Sys.sigfpe, "SIGFPE";
Sys.sighup, "SIGHUP"; Sys.sigill, "SIGILL"; Sys.sigint, "SIGINT";
Sys.sigkill, "SIGKILL"; Sys.sigpipe, "SIGPIPE"; Sys.sigquit, "SIGQUIT";
Sys.sigsegv, "SIGSEGV"; Sys.sigterm, "SIGTERM"; Sys.sigusr1, "SIGUSR1";
Sys.sigusr2, "SIGUSR2"; Sys.sigchld, "SIGCHLD"; Sys.sigcont, "SIGCONT";
Sys.sigstop, "SIGSTOP"; Sys.sigtstp, "SIGTSTP"; Sys.sigttin, "SIGTTIN";
Sys.sigttou, "SIGTTOU"; Sys.sigvtalrm, "SIGVTALRM";
Sys.sigprof, "SIGPROF"; Sys.sigbus, "SIGBUS"; Sys.sigpoll, "SIGPOLL";
Sys.sigsys, "SIGSYS"; Sys.sigtrap, "SIGTRAP"; Sys.sigurg, "SIGURG";
Sys.sigxcpu, "SIGXCPU"; Sys.sigxfsz, "SIGXFSZ"; ]
in
try raw_string ppf (List.assoc snum sigs) with
| Not_found -> pf ppf "SIG(%d)" snum
let pp_backtrace_str ppf s =
let stop = String.length s - 1 in
let rec loop left right =
if right = stop then raw_string ppf (String.sub s left (right - left)) else
if s.[right] <> '\n' then loop left (right + 1) else
begin
raw_string ppf (String.sub s left (right - left));
cut ppf ();
loop (right + 1) (right + 1)
end
in
if s = "" then (raw_string ppf "No backtrace available.") else
loop 0 0
let backtrace =
vbox @@ (using Printexc.raw_backtrace_to_string) pp_backtrace_str
let exn ppf e = raw_string ppf (Printexc.to_string e)
let exn_backtrace ppf (e, bt) =
pf ppf "@[<v>Exception: %a@,%a@]"
exn e pp_backtrace_str (Printexc.raw_backtrace_to_string bt)
let pair ?sep:(pp_sep = cut) pp_fst pp_snd ppf (fst, snd) =
pp_fst ppf fst; pp_sep ppf (); pp_snd ppf snd
let none ppf () = raw_string ppf "<none>"
let option ?none:(pp_none = nop) pp_v ppf = function
| None -> pp_none ppf ()
| Some v -> pp_v ppf v
let either ~left ~right ppf = function
| Either.Left v -> left ppf v
| Either.Right v -> right ppf v
let result ~ok ~error ppf = function Ok v -> ok ppf v | Error e -> error ppf e
let list ?(empty = nop) ?sep:pp_sep pp_elt ppf = function
| [] -> empty ppf ()
| l -> Format.pp_print_list ?pp_sep pp_elt ppf l
let array ?(empty = nop) ?sep pp_elt ppf a = match Array.length a with
| 0 -> empty ppf ()
| n -> iter ?sep Array.iter pp_elt ppf a
module OCaml = struct
let unit ppf () = string ppf "()"
let bool = Format.pp_print_bool
let int = Format.pp_print_int
let int32 ppf i = pf ppf "%ldl" i
let uint32 ppf i = pf ppf "0x%lxl" i
let int64 ppf i = pf ppf "%LdL" i
let uint64 ppf i = pf ppf "0x%LxL" i
let nativeint ppf i = pf ppf "%ndn" i
let nativeuint ppf i = pf ppf "0x%nxn" i
let float ppf f = pf ppf "%F" f
let hex_float ppf f = pf ppf "%#F" f
let char ppf = function
| '\'' -> string ppf {|'\''|}
| ' ' .. '~' as c -> raw_char ppf '\''; raw_char ppf c; raw_char ppf '\''
| '\n' -> string ppf {|'\n'|}
| '\r' -> string ppf {|'\r'|}
| '\t' -> string ppf {|'\t'|}
| c -> raw_char ppf '\''; pp_hex_escaped_char ppf c; raw_char ppf '\''
let ascii_string ppf s =
raw_char ppf '\"';
for i = 0 to String.length s - 1 do match s.[i] with
| '\'' as c -> raw_char ppf c
| '\"' -> raw_string ppf {|\"|}
| c -> char ppf c
done;
raw_char ppf '\"'
let string ppf s =
raw_char ppf '\"';
_text_string ~ansi:false ~for_literal:true ppf s;
raw_char ppf '\"'
let binary_string ppf s =
raw_char ppf '\"';
for i = 0 to String.length s - 1 do pp_hex_escaped_char ppf s.[i] done;
raw_char ppf '\"'
let option pp_v ppf = function
| None -> raw_string ppf "None"
| Some v -> pf ppf "@[<2>Some %a@]" pp_v v
let either ~left ~right ppf = function
| Either.Left v -> pf ppf "@[<2>Either.Left@ %a@]" left v
| Either.Right v -> pf ppf "@[<2>Either.Right@ %a@]" right v
let result ~ok ~error ppf = function
| Ok v -> pf ppf "@[<2>Ok@ %a@]" ok v
| Error e -> pf ppf "@[<2>Error@ %a@]" error e
let list pp_v ppf l =
let pp_sep ppf () = pf ppf ";@ " in
pf ppf "@[<1>[%a]@]" (Format.pp_print_list ~pp_sep pp_v) l
let array pp_v ppf a =
let sep ppf () = pf ppf ";@ " in
pf ppf "@[<2>[|%a|]@]" (iter ~sep Array.iter pp_v) a
let pair fst snd ppf (a, b) = pf ppf "@[<1>(%a,@ %a)@]" fst a snd b
let t2 = pair
let t3 v0 v1 v2 ppf (a, b, c) = pf ppf "@[<1>(%a,@ %a,@ %a)@]" v0 a v1 b v2 c
let t4 v0 v1 v2 v3 ppf (a, b, c, d) =
pf ppf "@[<1>(%a,@ %a,@ %a,@ %a)@]" v0 a v1 b v2 c v3 d
let t5 v0 v1 v2 v3 v4 ppf (a, b, c, d, e) =
pf ppf "@[<1>(%a,@ %a,@ %a,@ %a,@ %a)@]" v0 a v1 b v2 c v3 d v4 e
let t6 v0 v1 v2 v3 v4 v5 ppf (a, b, c, d, e, f) =
pf ppf "@[<1>(%a,@ %a,@ %a,@ %a,@ %a, @%a)@]" v0 a v1 b v2 c v3 d v4 e v5 f
end
let ilog10 x =
let rec loop p x = if x = 0 then p else loop (p + 1) (x / 10) in
loop (-1) x
let ipow10 n =
let rec loop acc n = if n = 0 then acc else loop (acc * 10) (n - 1) in
loop 1 n
let si_symb_max = 16
let si_symb =
[| "y"; "z"; "a"; "f"; "p"; "n"; "\xCE\xBC"; "m"; ""; "k"; "M"; "G"; "T";
"P"; "E"; "Z"; "Y" |]
let rec pp_at_factor ~scale u symb factor ppf s =
let m = s / factor in
let n = s mod factor in
match m with
| m when m >= 100 ->
let m_up = if n > 0 then m + 1 else m in
if m_up >= 1000 then si_size ~scale u ppf (m_up * factor) else
pf ppf "%d@<1>%s%s" m_up symb u
| m when m >= 10 ->
let f_factor = factor / 10 in
let f_m = n / f_factor in
let f_n = n mod f_factor in
let f_m_up = if f_n > 0 then f_m + 1 else f_m in
begin match f_m_up with
| 0 -> pf ppf "%d@<1>%s%s" m symb u
| f when f >= 10 -> si_size ~scale u ppf (m * factor + f * f_factor)
| f -> pf ppf "%d.%d@<1>%s%s" m f symb u
end
| m ->
let f_factor = factor / 100 in
let f_m = n / f_factor in
let f_n = n mod f_factor in
let f_m_up = if f_n > 0 then f_m + 1 else f_m in
match f_m_up with
| 0 -> pf ppf "%d@<1>%s%s" m symb u
| f when f >= 100 -> si_size ~scale u ppf (m * factor + f * f_factor)
| f when f mod 10 = 0 -> pf ppf "%d.%d@<1>%s%s" m (f / 10) symb u
| f -> pf ppf "%d.%02d@<1>%s%s" m f symb u
and si_size ~scale u ppf s = match scale < -8 || scale > 8 with
| true -> invalid_arg "~scale is %d, must be in [-8;8]" scale
| false ->
let pow_div_3 = if s = 0 then 0 else (ilog10 s / 3) in
let symb = (scale + 8) + pow_div_3 in
let symb, factor = match symb > si_symb_max with
| true -> si_symb_max, ipow10 ((8 - scale) * 3)
| false -> symb, ipow10 (pow_div_3 * 3)
in
if factor = 1
then pf ppf "%d%s%s" s si_symb.(symb) u
else pp_at_factor ~scale u si_symb.(symb) factor ppf s
let byte_size ppf s = si_size ~scale:0 "B" ppf s
let us_span = 1_000L
let ms_span = 1_000_000L
let sec_span = 1_000_000_000L
let min_span = 60_000_000_000L
let hour_span = 3600_000_000_000L
let day_span = 86_400_000_000_000L
let year_span = 31_557_600_000_000_000L
let rec pp_si_span unit_str unit_str_len si_unit si_higher_unit ppf span =
let geq x y = Int64.unsigned_compare x y >= 0 in
let m = Int64.unsigned_div span si_unit in
let n = Int64.unsigned_rem span si_unit in
let pp_unit ppf () = Format.pp_print_as ppf unit_str_len unit_str in
match m with
| m when geq m 100L ->
let m_up = if Int64.equal n 0L then m else Int64.succ m in
let span' = Int64.mul m_up si_unit in
if geq span' si_higher_unit then uint64_ns_span ppf span' else
(pf ppf "%Ld" m_up; pp_unit ppf ())
| m when geq m 10L ->
let f_factor = Int64.unsigned_div si_unit 10L in
let f_m = Int64.unsigned_div n f_factor in
let f_n = Int64.unsigned_rem n f_factor in
let f_m_up = if Int64.equal f_n 0L then f_m else Int64.succ f_m in
begin match f_m_up with
| 0L -> pf ppf "%Ld" m; pp_unit ppf ()
| f when geq f 10L ->
uint64_ns_span ppf Int64.(add (mul m si_unit) (mul f f_factor))
| f -> pf ppf "%Ld.%Ld" m f; pp_unit ppf ()
end
| m ->
let f_factor = Int64.unsigned_div si_unit 100L in
let f_m = Int64.unsigned_div n f_factor in
let f_n = Int64.unsigned_rem n f_factor in
let f_m_up = if Int64.equal f_n 0L then f_m else Int64.succ f_m in
match f_m_up with
| 0L -> pf ppf "%Ld" m; pp_unit ppf ()
| f when geq f 100L ->
uint64_ns_span ppf Int64.(add (mul m si_unit) (mul f f_factor))
| f when Int64.equal (Int64.rem f 10L) 0L ->
pf ppf "%Ld.%Ld" m (Int64.div f 10L); pp_unit ppf ()
| f ->
pf ppf "%Ld.%02Ld" m f; pp_unit ppf ()
and pp_non_si unit_str unit unit_lo_str unit_lo unit_lo_size ppf span =
let geq x y = Int64.unsigned_compare x y >= 0 in
let m = Int64.unsigned_div span unit in
let n = Int64.unsigned_rem span unit in
if Int64.equal n 0L then pf ppf "%Ld%s" m unit_str else
let f_m = Int64.unsigned_div n unit_lo in
let f_n = Int64.unsigned_rem n unit_lo in
let f_m_up = if Int64.equal f_n 0L then f_m else Int64.succ f_m in
match f_m_up with
| f when geq f unit_lo_size ->
uint64_ns_span ppf Int64.(add (mul m unit) (mul f unit_lo))
| f ->
pf ppf "%Ld%s%Ld%s" m unit_str f unit_lo_str
and uint64_ns_span ppf span =
let geq x y = Int64.unsigned_compare x y >= 0 in
let lt x y = Int64.unsigned_compare x y = -1 in
match span with
| s when lt s us_span -> pf ppf "%Ldns" s
| s when lt s ms_span -> pp_si_span "\xCE\xBCs" 2 us_span ms_span ppf s
| s when lt s sec_span -> pp_si_span "ms" 2 ms_span sec_span ppf s
| s when lt s min_span -> pp_si_span "s" 1 sec_span min_span ppf s
| s when lt s hour_span -> pp_non_si "min" min_span "s" sec_span 60L ppf s
| s when lt s day_span -> pp_non_si "h" hour_span "min" min_span 60L ppf s
| s when lt s year_span -> pp_non_si "d" day_span "h" hour_span 24L ppf s
| s ->
let m = Int64.unsigned_div s year_span in
let n = Int64.unsigned_rem s year_span in
if Int64.equal n 0L then pf ppf "%Lda" m else
let f_m = Int64.unsigned_div n day_span in
let f_n = Int64.unsigned_rem n day_span in
let f_m_up = if Int64.equal f_n 0L then f_m else Int64.succ f_m in
match f_m_up with
| f when geq f 366L -> pf ppf "%Lda" (Int64.succ m)
| f -> pf ppf "%Lda%Ldd" m f
let op_enum op ?(empty = nop) pp_v ppf = function
| [] -> empty ppf ()
| [v] -> pp_v ppf v
| vs ->
let rec loop ppf = function
| [v0; v1] -> pf ppf "%a@ %s@ %a" pp_v v0 op pp_v v1
| v :: vs -> pf ppf "%a,@ " pp_v v; loop ppf vs
| [] -> assert false
in
loop ppf vs
let and_enum ?empty pp_v ppf vs = op_enum "and" ?empty pp_v ppf vs
let or_enum ?empty pp_v ppf vs = op_enum "or" ?empty pp_v ppf vs
let did_you_mean pp_v ppf = function
| [] -> () | vs -> pf ppf "Did@ you@ mean %a ?" (or_enum pp_v) vs
let must_be pp_v ppf = function
| [] -> () | vs -> pf ppf "Must be %a." (or_enum pp_v) vs
let unknown ~kind pp_v ppf v = pf ppf "Unknown %a %a." kind () pp_v v
let unknown' ~kind pp_v ~hint ppf (v, hints) = match hints with
| [] -> unknown ~kind pp_v ppf v
| hints -> unknown ~kind pp_v ppf v; sp ppf (); (hint pp_v) ppf hints
let cardinal ?zero ~one ?other () =
let other = match other with
| Some other -> other
| None -> fun ppf i -> one ppf i; char ppf 's'
in
let zero = Option.value ~default:other zero in
fun ppf i -> match Int.abs i with
| 0 -> zero ppf 0 | 1 -> one ppf 1 | n -> other ppf i
let ordinal =
let one ppf i = int ppf i; string ppf "st" in
let two ppf i = int ppf i; string ppf "nd" in
let three ppf i = int ppf i; string ppf "rd" in
let other ppf i = int ppf i; string ppf "th" in
fun ?zero ?(one = one) ?(two = two) ?(three = three) ?(other = other) () ->
let zero = Option.value ~default:other zero in
fun ppf i ->
if i = 0 then zero ppf i else
let n = Int.abs i in
let mod10 = n mod 10 in
let mod100 = n mod 100 in
if mod10 = 1 && mod100 <> 11 then one ppf i else
if mod10 = 2 && mod100 <> 12 then two ppf i else
if mod10 = 3 && mod100 <> 13 then three ppf i else
other ppf i
type styler = Ansi | Plain
let styler' = Atomic.make @@
match Sys.getenv_opt "NO_COLOR" with
| Some s when s <> "" -> Plain
| _ ->
match Sys.getenv_opt "TERM" with
| Some "dumb" -> Plain
| None when Sys.backend_type <> Other "js_of_ocaml" -> Plain
| _ -> Ansi
let set_styler styler = Atomic.set styler' styler
let styler () = Atomic.get styler'
let strip_styles ppf =
let strip out_string s first len =
let max = first + len - 1 in
let flush first last =
if first > last then () else
out_string s first (last - first + 1)
in
let rec skip_esc i =
if i > max then scan i i else
let k = i + 1 in if s.[i] = 'm' then scan k k else skip_esc k
and scan first i =
if i > max then flush first max else match s.[i] with
| '\x1B' -> flush first (i - 1); skip_esc (i + 1)
| _ -> scan first (i + 1)
in
scan first first
in
let funs = Format.pp_get_formatter_out_functions ppf () in
let funs = { funs with out_string = strip funs.out_string } in
Format.pp_set_formatter_out_functions ppf funs
type color =
[ `Default
| `Black | `Black_bright
| `Red | `Red_bright
| `Green | `Green_bright
| `Yellow | `Yellow_bright
| `Blue | `Blue_bright
| `Magenta | `Magenta_bright
| `Cyan | `Cyan_bright
| `White | `White_bright ]
let rec sgr_base_int_of_color = function
| `Default -> 9
| `Black -> 0 | `Black_bright -> 60 + 0
| `Red -> 1 | `Red_bright -> 60 + 1
| `Green -> 2 | `Green_bright -> 60 + 2
| `Yellow -> 3 | `Yellow_bright -> 60 + 3
| `Blue -> 4 | `Blue_bright -> 60 + 4
| `Magenta -> 5 | `Magenta_bright -> 60 + 5
| `Cyan -> 6 | `Cyan_bright -> 60 + 6
| `White -> 7 | `White_bright -> 60 + 7
let sgr_of_fg_color c = string_of_int (30 + sgr_base_int_of_color c)
let sgr_of_bg_color c = string_of_int (40 + sgr_base_int_of_color c)
type style =
[ `Bold | `Faint | `Italic | `Underline | `Blink of [ `Slow | `Rapid ]
| `Reverse | `Fg of color | `Bg of color ]
let sgr_of_style = function
| `Bold -> "01"
| `Faint -> "02"
| `Italic -> "03"
| `Underline -> "04"
| `Blink `Slow -> "05"
| `Blink `Rapid -> "06"
| `Reverse -> "07"
| `Fg c -> sgr_of_fg_color c
| `Bg c -> sgr_of_bg_color c
let sgrs_of_styles styles = String.concat ";" (List.map sgr_of_style styles)
let ansi_esc = "\x1B["
let sgr_reset = "\x1B[m"
let st' styles pp_v ppf v = match Atomic.get styler' with
| Plain -> pp_v ppf v
| Ansi ->
let sgrs = String.concat "" [ansi_esc; sgrs_of_styles styles; "m"] in
Format.pp_print_as ppf 0 sgrs;
pp_v ppf v;
Format.pp_print_as ppf 0 sgr_reset
let st styles ppf s = match Atomic.get styler' with
| Plain -> raw_string ppf s
| Ansi ->
let sgrs = String.concat "" [ansi_esc; sgrs_of_styles styles; "m"] in
Format.pp_print_as ppf 0 sgrs;
Format.pp_print_string ppf s;
Format.pp_print_as ppf 0 sgr_reset
let code' pp_v ppf v = st' [`Bold] pp_v ppf v
let code ppf v = st [`Bold] ppf v
let hey ppf v = st [`Bold; `Fg `Red] ppf v
let puterr ppf () = st [`Bold; `Fg `Red] ppf "Error"; raw_char ppf ':'
let putwarn ppf () = st [`Bold; `Fg `Yellow] ppf "Warning"; raw_char ppf ':'
let putnote ppf () = st [`Bold; `Fg `Blue] ppf "Note"; raw_char ppf ':'
let field ?(label = st [`Fg `Yellow]) ?(sep = any ":@ ") l prj pp_v ppf v =
pf ppf "@[<1>%a%a%a@]" label l sep () pp_v (prj v)
let field ?(label = st [`Fg `Yellow]) ?(sep = any ":@ ") l prj pp_v ppf v =
pf ppf "@[<1>%a%a%a@]" label l sep () pp_v (prj v)