123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737(*---------------------------------------------------------------------------
Copyright (c) 2025 The more programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)(* Standard outputs and formatters *)letstdout=Format.std_formatterletstderr=Format.err_formatter(* Formatting *)letpf=Format.fprintfletpr=Format.printfletepr=Format.eprintfletstr=Format.asprintfletkpf=Format.kfprintfletkstr=Format.kasprintfletfailwith_linenfmt=kstrfailwith("%d:"^^fmt)nletfailwithfmt=kstrfailwithfmtletfailwith_notracefmt=kstr(funs->raise_notrace(Failures))fmtletinvalid_argfmt=kstrinvalid_argfmtleterrorfmt=kstr(funs->Errors)fmt(* Formatters *)type'at=Format.formatter->'a->unitletflushppf_=Format.pp_print_flushppf()letflush_nlppf_=Format.pp_print_newlineppf()letnopppf_=()letanyfmtppf_=pfppffmtletusingfpp_vppfv=pp_vppf(fv)letraw_char=Format.pp_print_charletraw_string=Format.pp_print_string(* Boxes *)letbox?(indent=0)pp_vppfv=Format.(pp_open_boxppfindent;pp_vppfv;pp_close_boxppf())lethboxpp_vppfv=Format.(pp_open_hboxppf();pp_vppfv;pp_close_boxppf())letvbox?(indent=0)pp_vppfv=Format.(pp_open_vboxppfindent;pp_vppfv;pp_close_boxppf())lethvbox?(indent=0)pp_vppfv=Format.(pp_open_hvboxppfindent;pp_vppfv;pp_close_boxppf())lethovbox?(indent=0)pp_vppfv=Format.(pp_open_hovboxppfindent;pp_vppfv;pp_close_boxppf())(* Separators *)letcutppf_=Format.pp_print_cutppf()letspppf_=Format.pp_print_spaceppf()letspsnppf_=Format.pp_print_breakppfn0letcommappf_=Format.pp_print_stringppf",";spppf()letsemippf_=Format.pp_print_stringppf";";spppf()(*
(* Doesn't work https://github.com/ocaml/ocaml/issues/13371 *)
let with_newline ~nl pp = fun ppf v ->
let outf = Format.pp_get_formatter_out_functions ppf () in
let out_newline () = outf.out_string nl 0 (String.length nl) in
let outf_with_nl = { outf with out_newline } in
let finally () = Format.pp_set_formatter_out_functions ppf outf in
Format.pp_set_formatter_out_functions ppf outf_with_nl;
Fun.protect ~finally @@ fun () -> pp ppf v
*)letsuffix_lines~suffixppppfv=letb=Buffer.create255inlet()=boxpp(Format.formatter_of_bufferb)vinletlines=Buffer.contentsbinletlines=String.split_on_char'\n'linesinletlast=List.lengthlines-1inletadd_newline_escil=ifi=lastthenlelsel^suffixinletlines=List.mapiadd_newline_esclinesinvbox(Format.pp_print_listraw_string)ppflines(* Sequencing *)letiter?sep:(pp_sep=cut)iterpp_eltppfv=letis_first=reftrueinletpp_eltv=if!is_firstthen(is_first:=false)elsepp_sepppf();pp_eltppfviniterpp_eltvletiter_bindings?sep:(pp_sep=cut)iterpp_bindingppfv=letis_first=reftrueinletpp_bindingkv=if!is_firstthen(is_first:=false)elsepp_sepppf();pp_bindingppf(k,v)initerpp_bindingvletappendpp_v0pp_v1ppfv=pp_v0ppfv;pp_v1ppfvlet(++)=appendletconcat?sepppsppfv=iter?sepList.iter(funppfpp->ppppfv)ppfpps(* Brackets *)letsurrounds1s2pp_vppfv=Format.(pp_print_stringppfs1;pp_vppfv;pp_print_stringppfs2)letparenspp_v=box~indent:1(surround"("")"pp_v)letbracketspp_v=box~indent:1(surround"[""]"pp_v)letoxford_bracketspp_v=box~indent:2(surround"[|""|]"pp_v)letbracespp_v=box~indent:1(surround"{""}"pp_v)letquote?(mark="\"")pp_v=letpp_markppf_=Format.pp_print_asppf1markinbox~indent:1(pp_mark++pp_v++pp_mark)(* Records *)letrecord?(sep=cut)pps=vbox(concat~seppps)(* Text *)letchar=raw_charlettext=Format.pp_print_textletstyled_textppfs=letrecloopppfsimax=ifi>maxthen()elseletansi=s.[i]='\x1B'&&i+1<max&&s.[i+1]='['inifnotansithenmatchs.[i]with|' 'wheni=max||s.[i+1]=' '||s.[i+1]='\n'->loopppfs(i+1)max|' '->spppf();loopppfs(i+1)max|'\n'wheni=max||s.[i+1]=' '->loopppfs(i+1)max|'\n'whens.[i+1]='\n'->Format.pp_force_newlineppf();ifi>0&&s.[i-1]<>'\n'thenFormat.pp_force_newlineppf();loopppfs(i+1)max|'\n'->spppf();loopppfs(i+1)max|c->charppfs.[i];loopppfs(i+1)maxelsebeginletk=ref(i+2)inwhile(!k<=max&&s.[!k]<>'m')doincrkdone;letesc=String.subsi(!k-i+1)inFormat.pp_print_asppf0esc;loopppfs(!k+1)maxendinloopppfs0(String.lengths-1)letlinesppfs=letrecstop_atsat~start~maxs=ifstart>maxthenstartelseifsats.[start]thenstartelsestop_atsat~start:(start+1)~maxsinletsubsstartstop~max=ifstart=stopthen""elseifstart=0&&stop>maxthenselseString.subsstart(stop-start)inletis_nlc=c='\n'inletmax=String.lengths-1inletrecloopstarts=matchstop_atis_nl~start~maxswith|stopwhenstop>max->Format.pp_print_stringppf(subsstartstop~max)|stop->Format.pp_print_stringppf(subsstartstop~max);Format.pp_force_newlineppf();loop(stop+1)sinloop0slettruncated~maxppfs=ifString.lengths<=maxthenraw_stringppfselse(fori=0tomax-2doraw_charppfs.[i]done;Format.pp_print_asppf1"…")letpp_hex_escaped_charppfc=pfppf"\\x%02x"(Char.codec)letascii_charppfc=ifB0__char.Ascii.is_printcthenraw_charppfcelsepp_hex_escaped_charppfclet_ascii_string~for_literalppfs=letescape_char~for_literalc=(c='\"'&&for_literal)||not(B0__char.Ascii.is_printc)inletesc~for_literalppfc=matchChar.codecwith|0x22whenfor_literal->raw_charppf'\\';raw_charppf'\"'|0x5Cwhenfor_literal->raw_charppf'\\';raw_charppf'\\'|0x0Dwhenfor_literal->raw_charppf'\\';raw_charppf'r'|0x0Awhenfor_literal->raw_charppf'\\';raw_charppf'n'|_->pp_hex_escaped_charppfcinfori=0toString.lengths-1doletc=s.[i]inifescape_char~for_literalcthenesc~for_literalppfcelseraw_charppfcdoneletascii_stringppfs=_ascii_string~for_literal:falseppfsletascii_string_literalppfs=raw_charppf'\"';_ascii_string~for_literal:trueppfs;raw_charppf'\"'lettext_ucharppfu=letesc=matchUchar.to_intuwith|uwhen0x0000<=u&&u<=0x001F->true(* C0 control characters *)|uwhen0x0080<=u&&u<=0x009F->true(* C1 control characters *)|0x2028->true(* line separator *)|0x2029->true(* paragraph separator *)|0x200E->true(* left-to-right mark *)|0x200F->true(* right-to-left mark *)|u->falseinifescthenpfppf"U+%04X"(Uchar.to_intu)elseletb=Bytes.create(Uchar.utf_8_byte_lengthu)inignore(Bytes.set_utf_8_ucharb0u);Format.pp_print_asppf1(Bytes.unsafe_to_stringb)let_text_string~ansi~for_literalppfs=letescape_uchar~for_literalu=matchUchar.to_intuwith|0x0022->for_literal|uwhen0x0000<=u&&u<=0x001F->true(* C0 control characters *)|uwhen0x0080<=u&&u<=0x009F->true(* C1 control characters *)|0x2028->true(* line separator *)|0x2029->true(* paragraph separator *)|_->falseinletescape~for_literalppfu=matchUchar.to_intuwith|0x0022whenfor_literal->raw_charppf'\\';raw_charppf'\"'|0x005Cwhenfor_literal->raw_stringppf"\\\\"|0x000Awhenfor_literal->raw_stringppf"\\n"|0x000Dwhenfor_literal->raw_stringppf"\\r"|u->pfppf"\\u{%04X}"uinletrecloop~for_literalppfimax=ifi>maxthen()elseletdec=String.get_utf_8_ucharsiinletu=Uchar.utf_decode_uchardecinletlen=Uchar.utf_decode_lengthdecinletnext=ifansi&&Uchar.to_intu=0x001B&&i+1<max&&s.[i+1]='['thenbeginletk=ref(i+2)inwhile(!k<=max&&s.[!k]<>'m')doincrkdone;letesc=String.subsi(!k-i+1)inFormat.pp_print_asppf0esc;!k+1endelsebeginlet()=ifescape_uchar~for_literaluthenescape~for_literalppfuelseifnot(Uchar.utf_decode_is_validdec)thenraw_stringppf"\u{FFFD}"elsefork=0tolen-1doraw_charppf(s.[i+k])doneini+lenendinloop~for_literalppfnextmaxinloop~for_literalppf0(String.lengths-1)lettext_stringppfs=_text_string~ansi:false~for_literal:falseppfslettext_bytesppfb=text_stringppf(Bytes.unsafe_to_stringb)letstring=raw_stringlettext_string_literalppfs=raw_charppf'\"';_text_string~ansi:false~for_literal:trueppfs;raw_charppf'\"'letstyled_text_stringppfs=_text_string~ansi:true~for_literal:falseppfsletstyled_text_string_literalppfs=raw_charppf'\"';_text_string~ansi:true~for_literal:trueppfs;raw_charppf'\"'(* Stdlib formatters *)letbool=Format.pp_print_boolletint=Format.pp_print_intletint32ppfi=pfppf"%ld"iletuint32ppfi=pfppf"%lu"iletint64ppfi=pfppf"%Ld"iletuint64ppfi=pfppf"%Lu"iletnativeintppfi=pfppf"%nd"iletnativeuintppfi=pfppf"%nu"iletfloatppff=pfppf"%g"fletbinary_string=letpp_byteppfc=pfppf"%02x"(Char.codec)initerString.iterpp_byteletbytesppfv=binary_stringppf(Bytes.unsafe_to_stringv)letsys_signalppfsnum=letsigs=[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";]intryraw_stringppf(List.assocsnumsigs)with|Not_found->pfppf"SIG(%d)"snumletpp_backtrace_strppfs=letstop=String.lengths-1(* there's a newline at the end *)inletrecloopleftright=ifright=stopthenraw_stringppf(String.subsleft(right-left))elseifs.[right]<>'\n'thenloopleft(right+1)elsebeginraw_stringppf(String.subsleft(right-left));cutppf();loop(right+1)(right+1)endinifs=""then(raw_stringppf"No backtrace available.")elseloop00letbacktrace=vbox@@(usingPrintexc.raw_backtrace_to_string)pp_backtrace_strletexnppfe=raw_stringppf(Printexc.to_stringe)letexn_backtraceppf(e,bt)=pfppf"@[<v>Exception: %a@,%a@]"exnepp_backtrace_str(Printexc.raw_backtrace_to_stringbt)letpair?sep:(pp_sep=cut)pp_fstpp_sndppf(fst,snd)=pp_fstppffst;pp_sepppf();pp_sndppfsndletnoneppf()=raw_stringppf"<none>"letoption?none:(pp_none=nop)pp_vppf=function|None->pp_noneppf()|Somev->pp_vppfvleteither~left~rightppf=function|Either.Leftv->leftppfv|Either.Rightv->rightppfvletresult~ok~errorppf=functionOkv->okppfv|Errore->errorppfeletlist?(empty=nop)?sep:pp_seppp_eltppf=function|[]->emptyppf()|l->Format.pp_print_list?pp_seppp_eltppflletarray?(empty=nop)?seppp_eltppfa=matchArray.lengthawith|0->emptyppf()|n->iter?sepArray.iterpp_eltppfamoduleOCaml=structletunitppf()=stringppf"()"letbool=Format.pp_print_boolletint=Format.pp_print_intletint32ppfi=pfppf"%ldl"iletuint32ppfi=pfppf"0x%lxl"iletint64ppfi=pfppf"%LdL"iletuint64ppfi=pfppf"0x%LxL"iletnativeintppfi=pfppf"%ndn"iletnativeuintppfi=pfppf"0x%nxn"iletfloatppff=pfppf"%F"flethex_floatppff=pfppf"%#F"fletcharppf=function|'\''->stringppf{|'\''|}|' '..'~'asc->raw_charppf'\'';raw_charppfc;raw_charppf'\''|'\n'->stringppf{|'\n'|}|'\r'->stringppf{|'\r'|}|'\t'->stringppf{|'\t'|}|c->raw_charppf'\'';pp_hex_escaped_charppfc;raw_charppf'\''letascii_stringppfs=raw_charppf'\"';fori=0toString.lengths-1domatchs.[i]with|'\''asc->raw_charppfc|'\"'->raw_stringppf{|\"|}|c->charppfcdone;raw_charppf'\"'letstringppfs=(* FIXME do not convert unknown bytes to U+FFFE *)raw_charppf'\"';_text_string~ansi:false~for_literal:trueppfs;raw_charppf'\"'letbinary_stringppfs=raw_charppf'\"';fori=0toString.lengths-1dopp_hex_escaped_charppfs.[i]done;raw_charppf'\"'letoptionpp_vppf=function|None->raw_stringppf"None"|Somev->pfppf"@[<2>Some %a@]"pp_vvleteither~left~rightppf=function|Either.Leftv->pfppf"@[<2>Either.Left@ %a@]"leftv|Either.Rightv->pfppf"@[<2>Either.Right@ %a@]"rightvletresult~ok~errorppf=function|Okv->pfppf"@[<2>Ok@ %a@]"okv|Errore->pfppf"@[<2>Error@ %a@]"erroreletlistpp_vppfl=letpp_sepppf()=pfppf";@ "inpfppf"@[<1>[%a]@]"(Format.pp_print_list~pp_seppp_v)lletarraypp_vppfa=letsepppf()=pfppf";@ "inpfppf"@[<2>[|%a|]@]"(iter~sepArray.iterpp_v)aletpairfstsndppf(a,b)=pfppf"@[<1>(%a,@ %a)@]"fstasndblett2=pairlett3v0v1v2ppf(a,b,c)=pfppf"@[<1>(%a,@ %a,@ %a)@]"v0av1bv2clett4v0v1v2v3ppf(a,b,c,d)=pfppf"@[<1>(%a,@ %a,@ %a,@ %a)@]"v0av1bv2cv3dlett5v0v1v2v3v4ppf(a,b,c,d,e)=pfppf"@[<1>(%a,@ %a,@ %a,@ %a,@ %a)@]"v0av1bv2cv3dv4elett6v0v1v2v3v4v5ppf(a,b,c,d,e,f)=pfppf"@[<1>(%a,@ %a,@ %a,@ %a,@ %a, @%a)@]"v0av1bv2cv3dv4ev5fend(* Magnitudes *)letilog10x=letreclooppx=ifx=0thenpelseloop(p+1)(x/10)inloop(-1)xletipow10n=letrecloopaccn=ifn=0thenaccelseloop(acc*10)(n-1)inloop1nletsi_symb_max=16letsi_symb=[|"y";"z";"a";"f";"p";"n";"\xCE\xBC";"m";"";"k";"M";"G";"T";"P";"E";"Z";"Y"|]letrecpp_at_factor~scaleusymbfactorppfs=letm=s/factorinletn=smodfactorinmatchmwith|mwhenm>=100->(* No fractional digit *)letm_up=ifn>0thenm+1elseminifm_up>=1000thensi_size~scaleuppf(m_up*factor)elsepfppf"%d@<1>%s%s"m_upsymbu|mwhenm>=10->(* One fractional digit w.o. trailing 0 *)letf_factor=factor/10inletf_m=n/f_factorinletf_n=nmodf_factorinletf_m_up=iff_n>0thenf_m+1elsef_minbeginmatchf_m_upwith|0->pfppf"%d@<1>%s%s"msymbu|fwhenf>=10->si_size~scaleuppf(m*factor+f*f_factor)|f->pfppf"%d.%d@<1>%s%s"mfsymbuend|m->(* Two or zero fractional digits w.o. trailing 0 *)letf_factor=factor/100inletf_m=n/f_factorinletf_n=nmodf_factorinletf_m_up=iff_n>0thenf_m+1elsef_minmatchf_m_upwith|0->pfppf"%d@<1>%s%s"msymbu|fwhenf>=100->si_size~scaleuppf(m*factor+f*f_factor)|fwhenfmod10=0->pfppf"%d.%d@<1>%s%s"m(f/10)symbu|f->pfppf"%d.%02d@<1>%s%s"mfsymbuandsi_size~scaleuppfs=matchscale<-8||scale>8with|true->invalid_arg"~scale is %d, must be in [-8;8]"scale|false->letpow_div_3=ifs=0then0else(ilog10s/3)inletsymb=(scale+8)+pow_div_3inletsymb,factor=matchsymb>si_symb_maxwith|true->si_symb_max,ipow10((8-scale)*3)|false->symb,ipow10(pow_div_3*3)iniffactor=1thenpfppf"%d%s%s"ssi_symb.(symb)uelsepp_at_factor~scaleusi_symb.(symb)factorppfsletbyte_sizeppfs=si_size~scale:0"B"ppfsletus_span=1_000Lletms_span=1_000_000Lletsec_span=1_000_000_000Lletmin_span=60_000_000_000Llethour_span=3600_000_000_000Lletday_span=86_400_000_000_000Lletyear_span=31_557_600_000_000_000Lletrecpp_si_spanunit_strunit_str_lensi_unitsi_higher_unitppfspan=letgeqxy=Int64.unsigned_comparexy>=0inletm=Int64.unsigned_divspansi_unitinletn=Int64.unsigned_remspansi_unitinletpp_unitppf()=Format.pp_print_asppfunit_str_lenunit_strinmatchmwith|mwhengeqm100L->(* No fractional digit *)letm_up=ifInt64.equaln0LthenmelseInt64.succminletspan'=Int64.mulm_upsi_unitinifgeqspan'si_higher_unitthenuint64_ns_spanppfspan'else(pfppf"%Ld"m_up;pp_unitppf())|mwhengeqm10L->(* One fractional digit w.o. trailing zero *)letf_factor=Int64.unsigned_divsi_unit10Linletf_m=Int64.unsigned_divnf_factorinletf_n=Int64.unsigned_remnf_factorinletf_m_up=ifInt64.equalf_n0Lthenf_melseInt64.succf_minbeginmatchf_m_upwith|0L->pfppf"%Ld"m;pp_unitppf()|fwhengeqf10L->uint64_ns_spanppfInt64.(add(mulmsi_unit)(mulff_factor))|f->pfppf"%Ld.%Ld"mf;pp_unitppf()end|m->(* Two or zero fractional digits w.o. trailing zero *)letf_factor=Int64.unsigned_divsi_unit100Linletf_m=Int64.unsigned_divnf_factorinletf_n=Int64.unsigned_remnf_factorinletf_m_up=ifInt64.equalf_n0Lthenf_melseInt64.succf_minmatchf_m_upwith|0L->pfppf"%Ld"m;pp_unitppf()|fwhengeqf100L->uint64_ns_spanppfInt64.(add(mulmsi_unit)(mulff_factor))|fwhenInt64.equal(Int64.remf10L)0L->pfppf"%Ld.%Ld"m(Int64.divf10L);pp_unitppf()|f->pfppf"%Ld.%02Ld"mf;pp_unitppf()andpp_non_siunit_strunitunit_lo_strunit_lounit_lo_sizeppfspan=letgeqxy=Int64.unsigned_comparexy>=0inletm=Int64.unsigned_divspanunitinletn=Int64.unsigned_remspanunitinifInt64.equaln0Lthenpfppf"%Ld%s"munit_strelseletf_m=Int64.unsigned_divnunit_loinletf_n=Int64.unsigned_remnunit_loinletf_m_up=ifInt64.equalf_n0Lthenf_melseInt64.succf_minmatchf_m_upwith|fwhengeqfunit_lo_size->uint64_ns_spanppfInt64.(add(mulmunit)(mulfunit_lo))|f->pfppf"%Ld%s%Ld%s"munit_strfunit_lo_stranduint64_ns_spanppfspan=letgeqxy=Int64.unsigned_comparexy>=0inletltxy=Int64.unsigned_comparexy=-1inmatchspanwith|swhenltsus_span->pfppf"%Ldns"s|swhenltsms_span->pp_si_span"\xCE\xBCs"2us_spanms_spanppfs|swhenltssec_span->pp_si_span"ms"2ms_spansec_spanppfs|swhenltsmin_span->pp_si_span"s"1sec_spanmin_spanppfs|swhenltshour_span->pp_non_si"min"min_span"s"sec_span60Lppfs|swhenltsday_span->pp_non_si"h"hour_span"min"min_span60Lppfs|swhenltsyear_span->pp_non_si"d"day_span"h"hour_span24Lppfs|s->letm=Int64.unsigned_divsyear_spaninletn=Int64.unsigned_remsyear_spaninifInt64.equaln0Lthenpfppf"%Lda"melseletf_m=Int64.unsigned_divnday_spaninletf_n=Int64.unsigned_remnday_spaninletf_m_up=ifInt64.equalf_n0Lthenf_melseInt64.succf_minmatchf_m_upwith|fwhengeqf366L->pfppf"%Lda"(Int64.succm)|f->pfppf"%Lda%Ldd"mf(* HCI fragments *)letop_enumop?(empty=nop)pp_vppf=function|[]->emptyppf()|[v]->pp_vppfv|vs->letrecloopppf=function|[v0;v1]->pfppf"%a@ %s@ %a"pp_vv0oppp_vv1|v::vs->pfppf"%a,@ "pp_vv;loopppfvs|[]->assertfalseinloopppfvsletand_enum?emptypp_vppfvs=op_enum"and"?emptypp_vppfvsletor_enum?emptypp_vppfvs=op_enum"or"?emptypp_vppfvsletdid_you_meanpp_vppf=function|[]->()|vs->pfppf"Did@ you@ mean %a ?"(or_enumpp_v)vsletmust_bepp_vppf=function|[]->()|vs->pfppf"Must be %a."(or_enumpp_v)vsletunknown~kindpp_vppfv=pfppf"Unknown %a %a."kind()pp_vvletunknown'~kindpp_v~hintppf(v,hints)=matchhintswith|[]->unknown~kindpp_vppfv|hints->unknown~kindpp_vppfv;spppf();(hintpp_v)ppfhintsletcardinal?zero~one?other()=letother=matchotherwith|Someother->other|None->funppfi->oneppfi;charppf's'inletzero=Option.value~default:otherzeroinfunppfi->matchInt.absiwith|0->zeroppf0|1->oneppf1|n->otherppfiletordinal=letoneppfi=intppfi;stringppf"st"inlettwoppfi=intppfi;stringppf"nd"inletthreeppfi=intppfi;stringppf"rd"inletotherppfi=intppfi;stringppf"th"infun?zero?(one=one)?(two=two)?(three=three)?(other=other)()->letzero=Option.value~default:otherzeroinfunppfi->ifi=0thenzeroppfielseletn=Int.absiinletmod10=nmod10inletmod100=nmod100inifmod10=1&&mod100<>11thenoneppfielseifmod10=2&&mod100<>12thentwoppfielseifmod10=3&&mod100<>13thenthreeppfielseotherppfi(* Text styling *)typestyler=Ansi|Plainletstyler'=Atomic.make@@matchSys.getenv_opt"NO_COLOR"with|Someswhens<>""->Plain|_->matchSys.getenv_opt"TERM"with|Some"dumb"->Plain|NonewhenSys.backend_type<>Other"js_of_ocaml"->Plain|_->Ansiletset_stylerstyler=Atomic.setstyler'stylerletstyler()=Atomic.getstyler'letstrip_stylesppf=(* Note: this code makes the assumption that out_string is always
going to be called without splitting escapes. Since we only
ever output escapes via pp_print_as this should not happen. *)letstripout_stringsfirstlen=letmax=first+len-1inletflushfirstlast=iffirst>lastthen()elseout_stringsfirst(last-first+1)inletrecskip_esci=ifi>maxthenscaniielseletk=i+1inifs.[i]='m'thenscankkelseskip_esckandscanfirsti=ifi>maxthenflushfirstmaxelsematchs.[i]with|'\x1B'->flushfirst(i-1);skip_esc(i+1)|_->scanfirst(i+1)inscanfirstfirstinletfuns=Format.pp_get_formatter_out_functionsppf()inletfuns={funswithout_string=stripfuns.out_string}inFormat.pp_set_formatter_out_functionsppffunstypecolor=[`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]letrecsgr_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+7letsgr_of_fg_colorc=string_of_int(30+sgr_base_int_of_colorc)letsgr_of_bg_colorc=string_of_int(40+sgr_base_int_of_colorc)typestyle=[`Bold|`Faint|`Italic|`Underline|`Blinkof[`Slow|`Rapid]|`Reverse|`Fgofcolor|`Bgofcolor]letsgr_of_style=function|`Bold->"01"|`Faint->"02"|`Italic->"03"|`Underline->"04"|`Blink`Slow->"05"|`Blink`Rapid->"06"|`Reverse->"07"|`Fgc->sgr_of_fg_colorc|`Bgc->sgr_of_bg_colorcletsgrs_of_stylesstyles=String.concat";"(List.mapsgr_of_stylestyles)letansi_esc="\x1B["letsgr_reset="\x1B[m"letst'stylespp_vppfv=matchAtomic.getstyler'with|Plain->pp_vppfv|Ansi->(* This doesn't compose well, we should get the current state
and restore it afterwards rather than resetting. But then we don't
have access to the current state. *)letsgrs=String.concat""[ansi_esc;sgrs_of_stylesstyles;"m"]inFormat.pp_print_asppf0sgrs;pp_vppfv;Format.pp_print_asppf0sgr_resetletststylesppfs=matchAtomic.getstyler'with|Plain->raw_stringppfs|Ansi->letsgrs=String.concat""[ansi_esc;sgrs_of_stylesstyles;"m"]inFormat.pp_print_asppf0sgrs;Format.pp_print_stringppfs;Format.pp_print_asppf0sgr_resetletcode'pp_vppfv=st'[`Bold]pp_vppfvletcodeppfv=st[`Bold]ppfvletheyppfv=st[`Bold;`Fg`Red]ppfvletputerrppf()=st[`Bold;`Fg`Red]ppf"Error";raw_charppf':'letputwarnppf()=st[`Bold;`Fg`Yellow]ppf"Warning";raw_charppf':'letputnoteppf()=st[`Bold;`Fg`Blue]ppf"Note";raw_charppf':'letfield?(label=st[`Fg`Yellow])?(sep=any":@ ")lprjpp_vppfv=pfppf"@[<1>%a%a%a@]"labellsep()pp_v(prjv)letfield?(label=st[`Fg`Yellow])?(sep=any":@ ")lprjpp_vppfv=pfppf"@[<1>%a%a%a@]"labellsep()pp_v(prjv)