123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Helpers for Format} *)type'asequence=('a->unit)->unitincludeFormattypet=Format.formattertype'aprinter=t->'a->unit(** {2 Combinators} *)letsilent_fmt_=()letreturnfmt_strout()=Format.fprintfout"%(%)"fmt_str(*$inject
let to_string_test s = CCFormat.sprintf_no_color "@[<h>%a@]%!" s ()
*)(*$= & ~printer:(fun s->CCFormat.sprintf "%S" s)
"a b" (to_string_test (return "a@ b"))
", " (to_string_test (return ",@ "))
"and then" (to_string_test (return "@{<Red>and then@}@,"))
"a b" (to_string_test (return "@[<h>a@ b@]"))
*)letunitfmt()=Format.pp_print_stringfmt"()"letintfmti=Format.pp_print_stringfmt(string_of_inti)letstring=Format.pp_print_stringletbool=Format.pp_print_boolletfloat3fmtf=Format.fprintffmt"%.3f"fletfloatfmtf=Format.pp_print_stringfmt(string_of_floatf)letchar=Format.pp_print_charletint32fmtn=Format.fprintffmt"%ld"nletint64fmtn=Format.fprintffmt"%Ld"nletnativeintfmtn=Format.fprintffmt"%nd"nletstring_quotedfmts=Format.fprintffmt"\"%s\""sletflush=Format.pp_print_flushletnewline=Format.pp_force_newlineletsubstringout(s,i,len):unit=stringout(String.subsilen)lettext=Format.pp_print_text(*$= & ~printer:(fun s->CCFormat.sprintf "%S" s)
"a\nb\nc" (sprintf_no_color "@[<v>%a@]%!" text "a b c")
"a b\nc" (sprintf_no_color "@[<h>%a@]%!" text "a b\nc")
*)letlist?(sep=return",@ ")ppfmtl=letrecpp_listl=matchlwith|x::((_::_)asl)->ppfmtx;sepfmt();pp_listl|x::[]->ppfmtx|[]->()inpp_listlletarray?(sep=return",@ ")ppfmta=fori=0toArray.lengtha-1doifi>0thensepfmt();ppfmta.(i)doneletarrayi?(sep=return",@ ")ppfmta=fori=0toArray.lengtha-1doifi>0thensepfmt();ppfmt(i,a.(i))doneletseq?(sep=return",@ ")ppfmtseq=letfirst=reftrueinseq(funx->if!firstthenfirst:=falseelsesepfmt();ppfmtx)letoptppfmtx=matchxwith|None->Format.pp_print_stringfmt"none"|Somex->Format.fprintffmt"some %a"ppxletpair?(sep=return",@ ")ppappbfmt(a,b)=Format.fprintffmt"%a%a%a"ppaasep()ppbblettriple?(sep=return",@ ")ppappbppcfmt(a,b,c)=Format.fprintffmt"%a%a%a%a%a"ppaasep()ppbbsep()ppccletquad?(sep=return",@ ")ppappbppcppdfmt(a,b,c,d)=Format.fprintffmt"%a%a%a%a%a%a%a"ppaasep()ppbbsep()ppccsep()ppddletwithinabpoutx=stringouta;poutx;stringoutbletmapfppfmtx=ppfmt(fx);()letvbox?(i=0)ppoutx=Format.pp_open_vboxouti;ppoutx;Format.pp_close_boxout()lethovbox?(i=0)ppoutx=Format.pp_open_hovboxouti;ppoutx;Format.pp_close_boxout()lethvbox?(i=0)ppoutx=Format.pp_open_hvboxouti;ppoutx;Format.pp_close_boxout()lethboxppoutx=Format.pp_open_hboxout();ppoutx;Format.pp_close_boxout()letof_to_stringfoutx=Format.pp_print_stringout(fx)letconstppxout()=ppoutxletsomeppout=function|None->()|Somex->ppoutxletlazy_forceppout(lazyx)=ppoutxletlazy_or?(default=return"<lazy>")ppoutx=ifLazy.is_valxthenppout(Lazy.forcex)elsedefaultout()(** {2 IO} *)letoutputfmtppx=ppfmtxletto_stringppx=letbuf=Buffer.create64inletfmt=Format.formatter_of_bufferbufinppfmtx;Format.pp_print_flushfmt();Buffer.contentsbufletfprintf=Format.fprintfletstdout=Format.std_formatterletstderr=Format.err_formatterletof_chan=Format.formatter_of_out_channelletwith_out_chanocf=letfmt=of_chanocintryletx=ffmtinFormat.pp_print_flushfmt();xwithe->Format.pp_print_flushfmt();raiseeletteeab=letfa=Format.pp_get_formatter_out_functionsa()inletfb=Format.pp_get_formatter_out_functionsb()inFormat.make_formatter(funstrilen->fa.Format.out_stringstrilen;fb.Format.out_stringstrilen)(fun()->fa.Format.out_flush();fb.Format.out_flush())(*$R
let buf1 = Buffer.create 42 in
let buf2 = Buffer.create 42 in
let f1 = Format.formatter_of_buffer buf1 in
let f2 = Format.formatter_of_buffer buf2 in
let fmt = tee f1 f2 in
Format.fprintf fmt "coucou@.";
assert_equal ~printer:CCFun.id "coucou\n" (Buffer.contents buf1);
assert_equal ~printer:CCFun.id "coucou\n" (Buffer.contents buf2);
*)letto_filefilenameformat=letoc=open_outfilenameinletfmt=Format.formatter_of_out_channelocinFormat.kfprintf(funfmt->Format.pp_print_flushfmt();close_out_noerroc)fmtformattypecolor=[`Black|`Red|`Yellow|`Green|`Blue|`Magenta|`Cyan|`White]letint_of_color_=function|`Black->0|`Red->1|`Green->2|`Yellow->3|`Blue->4|`Magenta->5|`Cyan->6|`White->7typestyle=[`FGofcolor(* foreground *)|`BGofcolor(* background *)|`Bold|`Reset]letcode_of_style:style->int=function|`FGc->30+int_of_color_c|`BGc->40+int_of_color_c|`Bold->1|`Reset->0letansi_l_to_str_=function|[]->"\x1b[0m"|[a]->Printf.sprintf"\x1b[%dm"(code_of_stylea)|[a;b]->Printf.sprintf"\x1b[%d;%dm"(code_of_stylea)(code_of_styleb)|l->letbuf=Buffer.create16inletpp_numc=Buffer.add_stringbuf(string_of_int(code_of_stylec))inBuffer.add_stringbuf"\x1b[";List.iteri(funic->ifi>0thenBuffer.add_charbuf';';pp_numc)l;Buffer.add_stringbuf"m";Buffer.contentsbufexceptionNo_such_style(* parse a tag *)letstyle_of_tag_s=matchString.trimswith|"reset"->[`Reset]|"black"->[`FG`Black]|"red"->[`FG`Red]|"green"->[`FG`Green]|"yellow"->[`FG`Yellow]|"blue"->[`FG`Blue]|"magenta"->[`FG`Magenta]|"cyan"->[`FG`Cyan]|"white"->[`FG`White]|"bold"->[`Bold]|"Black"->[`FG`Black;`Bold]|"Red"->[`FG`Red;`Bold]|"Green"->[`FG`Green;`Bold]|"Yellow"->[`FG`Yellow;`Bold]|"Blue"->[`FG`Blue;`Bold]|"Magenta"->[`FG`Magenta;`Bold]|"Cyan"->[`FG`Cyan;`Bold]|"White"->[`FG`White;`Bold]|_->raiseNo_such_styleletcolor_enabled=reffalse(* either prints the tag of [s] or delegate to [or_else] *)letmark_open_tagst~or_elses=tryletstyle=style_of_tag_sinStack.pushstylest;if!color_enabledthenansi_l_to_str_styleelse""withNo_such_style->or_elsesletmark_close_tagst~or_elses=(* check if it's indeed about color *)matchstyle_of_tag_swith|_->letstyle=tryignore(Stack.popst);(* pop current style (if well-scoped...) *)Stack.topst(* look at previous style *)withStack.Empty->[`Reset]inif!color_enabledthenansi_l_to_str_styleelse""|exceptionNo_such_style->or_elses(* add color handling to formatter [ppf] *)letset_color_tag_handlingppf=letopenFormatinletfunctions=CCShimsFormat_.pp_get_formatter_tag_functionsppf()inletst=Stack.create()in(* stack of styles *)letfunctions'=CCShimsFormat_.cc_update_funsfunctions(mark_open_tagst)(mark_close_tagst)inpp_set_mark_tagsppftrue;(* enable tags *)CCShimsFormat_.pp_set_formatter_tag_functionsppffunctions'letset_color_default=letfirst=reftrueinfunb->ifb&¬!color_enabledthen(color_enabled:=true;if!firstthen(first:=false;set_color_tag_handlingstdout;set_color_tag_handlingstderr;);)elseifnotb&&!color_enabledthencolor_enabled:=false(*$R
set_color_default true;
let s = sprintf
"what is your @{<White>favorite color@}? @{<blue>blue@}! No, @{<red>red@}! Ahhhhhhh@."
in
assert_equal ~printer:CCFun.id
"what is your \027[37;1mfavorite color\027[0m? \027[34mblue\027[0m! No, \027[31mred\027[0m! Ahhhhhhh\n"
s
*)letwith_colorsppoutx=CCShimsFormat_.pp_open_tagouts;ppoutx;CCShimsFormat_.pp_close_tagout()letwith_colorfsoutfmt=CCShimsFormat_.pp_open_tagouts;Format.kfprintf(funout->CCShimsFormat_.pp_close_tagout())outfmt(* c: whether colors are enabled *)letsprintf_cformat=letbuf=Buffer.create64inletfmt=Format.formatter_of_bufferbufinifc&&!color_enabledthenset_color_tag_handlingfmt;Format.kfprintf(fun_fmt->Format.pp_print_flushfmt();Buffer.contentsbuf)fmtformatletwith_color_ksf~fsfmt=letbuf=Buffer.create64inletout=Format.formatter_of_bufferbufinif!color_enabledthenset_color_tag_handlingout;CCShimsFormat_.pp_open_tagouts;Format.kfprintf(funout->CCShimsFormat_.pp_close_tagout();Format.pp_print_flushout();f(Buffer.contentsbuf))outfmtletwith_color_sfsfmt=with_color_ksf~f:(funs->s)sfmtletsprintffmt=sprintf_truefmtletsprintf_no_colorfmt=sprintf_falsefmtletsprintf_dyn_color~colorsfmt=sprintf_colorsfmtletfprintf_dyn_color~colorsoutfmt=letold_tags=Format.pp_get_mark_tagsout()inFormat.pp_set_mark_tagsoutcolors;(* enable/disable tags *)Format.kfprintf(funout->Format.pp_set_mark_tagsoutold_tags)outfmt(*$T
sprintf "yolo %s %d" "a b" 42 = "yolo a b 42"
sprintf "%d " 0 = "0 "
sprintf_no_color "%d " 0 = "0 "
*)(*$R
set_color_default true;
assert_equal "\027[31myolo\027[0m" (sprintf "@{<red>yolo@}");
assert_equal "yolo" (sprintf_no_color "@{<red>yolo@}");
*)letksprintf?margin~ffmt=letbuf=Buffer.create32inletout=Format.formatter_of_bufferbufinif!color_enabledthenset_color_tag_handlingout;beginmatchmarginwithNone->()|Somem->pp_set_marginoutmend;Format.kfprintf(fun_->Format.pp_print_flushout();f(Buffer.contentsbuf))outfmt(*$= & ~printer:CCFormat.(to_string (opt string))
(Some "hello world") \
(ksprintf ~f:(fun s -> Some s) "hello %a" CCFormat.string "world")
*)moduleDump=structtype'at='aprinterletunit=unitletint=intletstring=string_quotedletbool=boolletfloat=floatletchar=charletint32=int32letint64=int64letnativeint=nativeintletlistpp=within"[""]"(hovbox(list~sep:(return";@,")pp))letarraypp=within"[|""|]"(hovbox(array~sep:(return";@,")pp))letoptionppoutx=matchxwith|None->Format.pp_print_stringout"None"|Somex->Format.fprintfout"Some %a"ppxletpairp1p2=within"("")"(hovbox(pairp1p2))lettriplep1p2p3=within"("")"(hovbox(triplep1p2p3))letquadp1p2p3p4=within"("")"(hovbox(quadp1p2p3p4))letresult'pokperrorout=function|Okx->Format.fprintfout"(@[Ok %a@])"pokx|Errore->Format.fprintfout"(@[Error %a@])"perroreletresultpok=result'pokstringletto_string=to_stringend(*$= & ~printer:(fun s->s)
"[1;2;3]" (to_string Dump.(list int) [1;2;3])
"Some 1" (to_string Dump.(option int) (Some 1))
"[None;Some \"a b\"]" (to_string Dump.(list (option string)) [None; Some "a b"])
"[(Ok \"a b c\");(Error \"nope\")]" \
(to_string Dump.(list (result string)) [Ok "a b c"; Error "nope"])
*)