package fmt
OCaml Format pretty-printer combinators
Install
dune-project
Dependency
Authors
Maintainers
Sources
fmt-0.11.0.tbz
sha512=3f40155fc6a7315202e410585964307d63416c8001fd243667ed9d8d1a02b67deecacb25e9c2feb409c537bbdfb7817d91168de4ddd643532ff51d6c1c696a4a
doc/src/fmt/fmt.ml.html
Source file 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 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
(*--------------------------------------------------------------------------- Copyright (c) 2014 The fmt programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) let invalid_arg' = invalid_arg (* Errors *) let err_str_formatter = "Format.str_formatter can't be set." (* Standard outputs *) let stdout = Format.std_formatter let stderr = Format.err_formatter (* Formatting *) 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 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 let error_msg fmt = kstr (fun s -> Error (`Msg s)) fmt (* Formatters *) type 'a t = Format.formatter -> 'a -> unit let flush ppf _ = Format.pp_print_flush ppf () let nop fmt ppf = () let any fmt ppf _ = pf ppf fmt let using f pp ppf v = pp ppf (f v) let const pp_v v ppf _ = pp_v ppf v let if' bool pp = if bool then pp else nop let fmt fmt ppf = pf ppf fmt (* Separators *) 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 () (* Sequencing *) 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 (* Boxes *) 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 ()) (* Brackets *) 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) (* Stdlib types formatters *) let bool = Format.pp_print_bool let int = Format.pp_print_int let nativeint ppf v = pf ppf "%nd" v let int32 ppf v = pf ppf "%ld" v let int64 ppf v = pf ppf "%Ld" v let uint ppf v = pf ppf "%u" v let uint32 ppf v = pf ppf "%lu" v let uint64 ppf v = pf ppf "%Lu" v let unativeint ppf v = pf ppf "%nu" v let char = Format.pp_print_char let string = Format.pp_print_string let buffer ppf b = string ppf (Buffer.contents b) let exn ppf e = string ppf (Printexc.to_string e) let exn_backtrace ppf (e, bt) = let pp_backtrace_str ppf s = let stop = String.length s - 1 (* there's a newline at the end *) in let rec loop left right = if right = stop then string ppf (String.sub s left (right - left)) else if s.[right] <> '\n' then loop left (right + 1) else begin string ppf (String.sub s left (right - left)); cut ppf (); loop (right + 1) (right + 1) end in if s = "" then (string ppf "No backtrace available.") else loop 0 0 in pf ppf "@[<v>Exception: %a@,%a@]" exn e pp_backtrace_str (Printexc.raw_backtrace_to_string bt) let float ppf v = pf ppf "%g" v let round x = floor (x +. 0.5) let round_dfrac d x = if x -. (round x) = 0. then x else (* x is an integer. *) let m = 10. ** (float_of_int d) in (* m moves 10^-d to 1. *) (floor ((x *. m) +. 0.5)) /. m let round_dsig d x = if x = 0. then 0. else let m = 10. ** (floor (log10 (abs_float x))) in (* to normalize x. *) (round_dfrac d (x /. m)) *. m let float_dfrac d ppf f = pf ppf "%g" (round_dfrac d f) let float_dsig d ppf f = pf ppf "%g" (round_dsig d f) 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 option ?none:(pp_none = nop) pp_v ppf = function | None -> pp_none ppf () | Some v -> pp_v ppf v let result ~ok ~error ppf = function | Ok v -> ok ppf v | Error e -> error ppf e let list ?sep pp_elt = iter ?sep List.iter pp_elt let array ?sep pp_elt = iter ?sep Array.iter pp_elt let seq ?sep pp_elt = iter ?sep Seq.iter pp_elt let hashtbl ?sep pp_binding = iter_bindings ?sep Hashtbl.iter pp_binding let queue ?sep pp_elt = iter Queue.iter pp_elt let stack ?sep pp_elt = iter Stack.iter pp_elt (* Stdlib type dumpers *) module Dump = struct (* Stdlib types *) let sig_names = Sys.[ sigabrt, "SIGABRT"; sigalrm, "SIGALRM"; sigfpe, "SIGFPE"; sighup, "SIGHUP"; sigill, "SIGILL"; sigint, "SIGINT"; sigkill, "SIGKILL"; sigpipe, "SIGPIPE"; sigquit, "SIGQUIT"; sigsegv, "SIGSEGV"; sigterm, "SIGTERM"; sigusr1, "SIGUSR1"; sigusr2, "SIGUSR2"; sigchld, "SIGCHLD"; sigcont, "SIGCONT"; sigstop, "SIGSTOP"; sigtstp, "SIGTSTP"; sigttin, "SIGTTIN"; sigttou, "SIGTTOU"; sigvtalrm, "SIGVTALRM"; sigprof, "SIGPROF"; sigbus, "SIGBUS"; sigpoll, "SIGPOLL"; sigsys, "SIGSYS"; sigtrap, "SIGTRAP"; sigurg, "SIGURG"; sigxcpu, "SIGXCPU"; sigxfsz, "SIGXFSZ"; ] let signal ppf s = match List.assq_opt s sig_names with | Some name -> string ppf name | None -> pf ppf "SIG(%d)" s let uchar ppf u = pf ppf "U+%04X" (Uchar.to_int u) let string ppf s = pf ppf "%S" s let pair pp_fst pp_snd = parens (using fst (box pp_fst) ++ comma ++ using snd (box pp_snd)) let option pp_v ppf = function | None -> pf ppf "None" | Some v -> pf ppf "@[<2>Some@ @[%a@]@]" pp_v 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 (* Sequencing *) let iter iter_f pp_name pp_elt = let pp_v = iter ~sep:sp iter_f (box pp_elt) in parens (pp_name ++ sp ++ pp_v) let iter_bindings iter_f pp_name pp_k pp_v = let pp_v = iter_bindings ~sep:sp iter_f (pair pp_k pp_v) in parens (pp_name ++ sp ++ pp_v) (* Stdlib data structures *) let list pp_elt = brackets (list ~sep:semi (box pp_elt)) let array pp_elt = oxford_brackets (array ~sep:semi (box pp_elt)) let seq pp_elt = brackets (seq ~sep:semi (box pp_elt)) let hashtbl pp_k pp_v = iter_bindings Hashtbl.iter (any "hashtbl") pp_k pp_v let stack pp_elt = iter Stack.iter (any "stack") pp_elt let queue pp_elt = iter Queue.iter (any "queue") pp_elt (* Records *) let field ?(label = string) l prj pp_v ppf v = pf ppf "@[<1>%a =@ %a@]" label l pp_v (prj v) let record pps = box ~indent:2 (surround "{ " " }" @@ vbox (concat ~sep:(any ";@,") pps)) end (* Magnitudes *) 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"; "u"; "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 -> (* No fractional digit *) 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%s%s" m_up symb u | m when m >= 10 -> (* One fractional digit w.o. trailing 0 *) 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%s%s" m symb u | f when f >= 10 -> si_size ~scale u ppf (m * factor + f * f_factor) | f -> pf ppf "%d.%d%s%s" m f symb u end | m -> (* Two or zero fractional digits w.o. trailing 0 *) 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%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%s%s" m (f / 10) symb u | f -> pf ppf "%d.%02d%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 bi_byte_size ppf s = (* XXX we should get rid of this. *) let _pp_byte_size k i ppf s = let pp_frac = float_dfrac 1 in let div_round_up m n = (m + n - 1) / n in let float = float_of_int in if s < k then pf ppf "%dB" s else let m = k * k in if s < m then begin let kstr = if i = "" then "k" (* SI *) else "K" (* IEC *) in let sk = s / k in if sk < 10 then pf ppf "%a%s%sB" pp_frac (float s /. float k) kstr i else pf ppf "%d%s%sB" (div_round_up s k) kstr i end else let g = k * m in if s < g then begin let sm = s / m in if sm < 10 then pf ppf "%aM%sB" pp_frac (float s /. float m) i else pf ppf "%dM%sB" (div_round_up s m) i end else let t = k * g in if s < t then begin let sg = s / g in if sg < 10 then pf ppf "%aG%sB" pp_frac (float s /. float g) i else pf ppf "%dG%sB" (div_round_up s g) i end else let p = k * t in if s < p then begin let st = s / t in if st < 10 then pf ppf "%aT%sB" pp_frac (float s /. float t) i else pf ppf "%dT%sB" (div_round_up s t) i end else begin let sp = s / p in if sp < 10 then pf ppf "%aP%sB" pp_frac (float s /. float p) i else pf ppf "%dP%sB" (div_round_up s p) i end in _pp_byte_size 1024 "i" ppf s (* XXX From 4.08 on use Int64.unsigned_* See Hacker's Delight for the implementation of these unsigned_* funs *) let unsigned_compare x0 x1 = Int64.(compare (sub x0 min_int) (sub x1 min_int)) let unsigned_div n d = match d < Int64.zero with | true -> if unsigned_compare n d < 0 then Int64.zero else Int64.one | false -> let q = Int64.(shift_left (div (shift_right_logical n 1) d) 1) in let r = Int64.(sub n (mul q d)) in if unsigned_compare r d >= 0 then Int64.succ q else q let unsigned_rem n d = Int64.(sub n (mul (unsigned_div n d) d)) 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 si_unit si_higher_unit ppf span = let geq x y = unsigned_compare x y >= 0 in let m = unsigned_div span si_unit in let n = unsigned_rem span si_unit in match m with | m when geq m 100L -> (* No fractional digit *) 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%s" m_up unit_str | m when geq m 10L -> (* One fractional digit w.o. trailing zero *) let f_factor = unsigned_div si_unit 10L in let f_m = unsigned_div n f_factor in let f_n = 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%s" m unit_str | f when geq f 10L -> uint64_ns_span ppf Int64.(add (mul m si_unit) (mul f f_factor)) | f -> pf ppf "%Ld.%Ld%s" m f unit_str end | m -> (* Two or zero fractional digits w.o. trailing zero *) let f_factor = unsigned_div si_unit 100L in let f_m = unsigned_div n f_factor in let f_n = 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%s" m unit_str | 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%s" m (Int64.div f 10L) unit_str | f -> pf ppf "%Ld.%02Ld%s" m f unit_str and pp_non_si unit_str unit unit_lo_str unit_lo unit_lo_size ppf span = let geq x y = unsigned_compare x y >= 0 in let m = unsigned_div span unit in let n = unsigned_rem span unit in if Int64.equal n 0L then pf ppf "%Ld%s" m unit_str else let f_m = unsigned_div n unit_lo in let f_n = 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 = unsigned_compare x y >= 0 in let lt x y = 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 "us" us_span ms_span ppf s | s when lt s sec_span -> pp_si_span "ms" ms_span sec_span ppf s | s when lt s min_span -> pp_si_span "s" 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 = unsigned_div s year_span in let n = unsigned_rem s year_span in if Int64.equal n 0L then pf ppf "%Lda" m else let f_m = unsigned_div n day_span in let f_n = 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 (* Binary formatting *) type 'a vec = int * (int -> 'a) let iter_vec f (n, get) = for i = 0 to n - 1 do f i (get i) done let vec ?sep = iter_bindings ?sep iter_vec let on_string = using String.(fun s -> length s, get s) let on_bytes = using Bytes.(fun b -> length b, get b) let sub_vecs w (n, get) = (n - 1) / w + 1, fun j -> let off = w * j in min w (n - off), fun i -> get (i + off) let prefix0x = [ 0xf , fmt "%01x"; 0xff , fmt "%02x"; 0xfff , fmt "%03x"; 0xffff , fmt "%04x"; 0xfffff , fmt "%05x"; 0xffffff , fmt "%06x"; 0xfffffff , fmt "%07x"; ] let padded0x ~max = match List.find_opt (fun (x, _) -> max <= x) prefix0x with | Some (_, pp) -> pp | None -> fmt "%08x" let ascii ?(w = 0) ?(subst = const char '.') () ppf (n, _ as v) = let pp_char ppf (_, c) = if '\x20' <= c && c < '\x7f' then char ppf c else subst ppf () in vec pp_char ppf v; if n < w then sps (w - n) ppf () let octets ?(w = 0) ?(sep = sp) () ppf (n, _ as v) = let pp_sep ppf i = if i > 0 && i mod 2 = 0 then sep ppf () in let pp_char ppf (i, c) = pp_sep ppf i; pf ppf "%02x" (Char.code c) in vec ~sep:nop pp_char ppf v; for i = n to w - 1 do pp_sep ppf i; sps 2 ppf () done let addresses ?addr ?(w = 16) pp_vec ppf (n, _ as v) = let addr = match addr with | Some pp -> pp | _ -> padded0x ~max:(((n - 1) / w) * w) ++ const string ": " in let pp_sub ppf (i, sub) = addr ppf (i * w); box pp_vec ppf sub in vbox (vec pp_sub) ppf (sub_vecs w v) let hex ?(w = 16) () = addresses ~w ((octets ~w () |> box) ++ sps 2 ++ (ascii ~w () |> box)) (* Text and lines *) let is_nl c = c = '\n' let is_nl_or_sp c = is_nl c || c = ' ' let is_white = function ' ' | '\t' .. '\r' -> true | _ -> false let not_white c = not (is_white c) let not_white_or_nl c = is_nl c || not_white c 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 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) let words ppf s = let max = String.length s - 1 in let rec loop start s = match stop_at is_white ~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); match stop_at not_white ~start:stop ~max s with | stop when stop > max -> () | stop -> Format.pp_print_space ppf (); loop stop s in let start = stop_at not_white ~start:0 ~max s in if start > max then () else loop start s let paragraphs ppf s = let max = String.length s - 1 in let rec loop start s = match stop_at is_white ~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); match stop_at not_white_or_nl ~start:stop ~max s with | stop when stop > max -> () | stop -> if s.[stop] <> '\n' then (Format.pp_print_space ppf (); loop stop s) else match stop_at not_white_or_nl ~start:(stop + 1) ~max s with | stop when stop > max -> () | stop -> if s.[stop] <> '\n' then (Format.pp_print_space ppf (); loop stop s) else match stop_at not_white ~start:(stop + 1) ~max s with | stop when stop > max -> () | stop -> Format.pp_force_newline ppf (); Format.pp_force_newline ppf (); loop stop s in let start = stop_at not_white ~start:0 ~max s in if start > max then () else loop start s let text ppf s = let max = String.length s - 1 in let rec loop start s = match stop_at is_nl_or_sp ~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); begin match s.[stop] with | ' ' -> Format.pp_print_space ppf () | '\n' -> Format.pp_force_newline ppf () | _ -> assert false end; loop (stop + 1) s in loop 0 s let lines ppf s = 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 = match String.length s <= max with | true -> Format.pp_print_string ppf s | false -> for i = 0 to max - 4 do Format.pp_print_char ppf s.[i] done; Format.pp_print_string ppf "..." let text_loc ppf ((l0, c0), (l1, c1)) = if (l0 : int) == (l1 : int) && (c0 : int) == (c1 : int) then pf ppf "%d.%d" l0 c0 else pf ppf "%d.%d-%d.%d" l0 c0 l1 c1 (* HCI fragments *) let one_of ?(empty = nop) pp_v ppf = function | [] -> empty ppf () | [v] -> pp_v ppf v | [v0; v1] -> pf ppf "@[either %a or@ %a@]" pp_v v0 pp_v v1 | _ :: _ as vs -> let rec loop ppf = function | [v] -> pf ppf "or@ %a" pp_v v | v :: vs -> pf ppf "%a,@ " pp_v v; loop ppf vs | [] -> assert false in pf ppf "@[one@ of@ %a@]" loop vs let did_you_mean ?(pre = any "Unknown") ?(post = nop) ~kind pp_v ppf (v, hints) = match hints with | [] -> pf ppf "@[%a %s %a%a.@]" pre () kind pp_v v post () | hints -> pf ppf "@[%a %s %a%a.@ Did you mean %a ?@]" pre () kind pp_v v post () (one_of pp_v) 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 (* Conditional UTF-8 and styled formatting. *) module Imap = Map.Make (Int) type 'a attr = int * ('a -> string) * (string -> 'a) let id = ref 0 let attr (type a) enc dec = incr id; (!id, enc, dec) type Format.stag += | Fmt_store_get : 'a attr -> Format.stag | Fmt_store_set : 'a attr * 'a -> Format.stag let store () = let s = ref Imap.empty in fun ~other -> function | Fmt_store_get (id, _, _) -> Option.value ~default:"" (Imap.find_opt id !s) | Fmt_store_set ((id, enc, _), v) -> s := Imap.add id (enc v) !s; "ok" | stag -> other stag let setup_store ppf = let funs = Format.pp_get_formatter_stag_functions ppf () in let mark_open_stag = store () ~other:funs.mark_open_stag in Format.pp_set_formatter_stag_functions ppf { funs with mark_open_stag } let store_op op ppf = let funs = Format.pp_get_formatter_stag_functions ppf () in funs.mark_open_stag op let get (_, _, dec as attr) ppf = match store_op (Fmt_store_get attr) ppf with | "" -> None | s -> Some (dec s) let rec set attr v ppf = match store_op (Fmt_store_set (attr, v)) ppf with | "ok" -> () | _ -> setup_store ppf; set attr v ppf let def x = function Some y -> y | _ -> x let utf_8_attr = let enc = function true -> "t" | false -> "f" in let dec = function "t" -> true | "f" -> false | _ -> assert false in attr enc dec let utf_8 ppf = get utf_8_attr ppf |> def true let set_utf_8 ppf x = set utf_8_attr x ppf type style_renderer = [ `Ansi_tty | `None ] let style_renderer_attr = let enc = function `Ansi_tty -> "A" | `None -> "N" in let dec = function "A" -> `Ansi_tty | "N" -> `None | _ -> assert false in attr enc dec let style_renderer ppf = get style_renderer_attr ppf |> def `None let set_style_renderer ppf x = set style_renderer_attr x ppf let with_buffer ?like buf = let ppf = Format.formatter_of_buffer buf in (* N.B. this does slighty more it also makes buf use other installed semantic tag actions. *) match like with | None -> ppf | Some like -> let funs = Format.pp_get_formatter_stag_functions like () in Format.pp_set_formatter_stag_functions ppf funs; ppf let str_like ppf fmt = let buf = Buffer.create 64 in let bppf = with_buffer ~like:ppf buf in let flush ppf = Format.pp_print_flush ppf (); let s = Buffer.contents buf in Buffer.reset buf; s in Format.kfprintf flush bppf fmt (* Conditional UTF-8 formatting *) let if_utf_8 pp_u pp = fun ppf v -> (if utf_8 ppf then pp_u else pp) ppf v (* Styled formatting *) type color = [ `Black | `Blue | `Cyan | `Green | `Magenta | `Red | `White | `Yellow ] type style = [ `None | `Bold | `Faint | `Italic | `Underline | `Reverse | `Fg of [ color | `Hi of color ] | `Bg of [ color | `Hi of color ] | color (** deprecated *) ] let ansi_style_code = function | `Bold -> "1" | `Faint -> "2" | `Italic -> "3" | `Underline -> "4" | `Reverse -> "7" | `Fg `Black -> "30" | `Fg `Red -> "31" | `Fg `Green -> "32" | `Fg `Yellow -> "33" | `Fg `Blue -> "34" | `Fg `Magenta -> "35" | `Fg `Cyan -> "36" | `Fg `White -> "37" | `Bg `Black -> "40" | `Bg `Red -> "41" | `Bg `Green -> "42" | `Bg `Yellow -> "43" | `Bg `Blue -> "44" | `Bg `Magenta -> "45" | `Bg `Cyan -> "46" | `Bg `White -> "47" | `Fg (`Hi `Black) -> "90" | `Fg (`Hi `Red) -> "91" | `Fg (`Hi `Green) -> "92" | `Fg (`Hi `Yellow) -> "93" | `Fg (`Hi `Blue) -> "94" | `Fg (`Hi `Magenta) -> "95" | `Fg (`Hi `Cyan) -> "96" | `Fg (`Hi `White) -> "97" | `Bg (`Hi `Black) -> "100" | `Bg (`Hi `Red) -> "101" | `Bg (`Hi `Green) -> "102" | `Bg (`Hi `Yellow) -> "103" | `Bg (`Hi `Blue) -> "104" | `Bg (`Hi `Magenta) -> "105" | `Bg (`Hi `Cyan) -> "106" | `Bg (`Hi `White) -> "107" | `None -> "0" (* deprecated *) | `Black -> "30" | `Red -> "31" | `Green -> "32" | `Yellow -> "33" | `Blue -> "34" | `Magenta -> "35" | `Cyan -> "36" | `White -> "37" let pp_sgr ppf style = Format.pp_print_as ppf 0 "\027["; Format.pp_print_as ppf 0 style; Format.pp_print_as ppf 0 "m" let curr_style = attr Fun.id Fun.id let styled style pp_v ppf v = match style_renderer ppf with | `None -> pp_v ppf v | `Ansi_tty -> let prev = match get curr_style ppf with | None -> let zero = "0" in set curr_style zero ppf; zero | Some s -> s in let here = ansi_style_code style in let curr = match style with | `None -> here | _ -> String.concat ";" [prev; here] in let finally () = set curr_style prev ppf in set curr_style curr ppf; Fun.protect ~finally @@ fun () -> pp_sgr ppf here; pp_v ppf v; pp_sgr ppf prev (* Records *) let id = Fun.id let label = styled (`Fg `Yellow) string let field ?(label = label) ?(sep = any ":@ ") l prj pp_v ppf v = pf ppf "@[<1>%a%a%a@]" label l sep () pp_v (prj v) let record ?(sep = cut) pps = vbox (concat ~sep pps) (* Converting with string converters. *) let of_to_string f ppf v = string ppf (f v) let to_to_string pp_v v = str "%a" pp_v v (* Deprecated *) let strf = str let kstrf = kstr let strf_like = str_like let always = any let unit = any let prefix pp_p pp_v ppf v = pp_p ppf (); pp_v ppf v let suffix pp_s pp_v ppf v = pp_v ppf v; pp_s ppf () let styled_unit style fmt = styled style (any fmt)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>