Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file containers_pp.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603moduleB=BuffermoduleInt_map=Map.Make(CCInt)type'aiter=('a->unit)->unitmoduleOut=structtypet={char:char->unit;(** Output a single char. The char is assumed not to be ['\n']. *)sub_string:string->int->int->unit;(** Output a string slice (optim for [string]) *)string:string->unit;(** Output a string *)newline:unit->unit;(** Output a newline *)}letof_buffer(buf:Buffer.t):t=letchar=B.add_charbufinletsub_string=B.add_substringbufinletstring=B.add_stringbufinletnewline()=B.add_charbuf'\n'in{char;sub_string;string;newline}let[@inline]charselfc=self.charclet[@inline]stringselfs=self.stringslet[@inline]sub_stringselfsilen=self.sub_stringsilenlet[@inline]newlineself=self.newline()endmoduleExt=structtypeview=..type'akey={id:int;inject:'a->view;extract:view->'aoption;}typemap=viewInt_map.tletempty:map=Int_map.emptyletgetk(self:map):_option=tryk.extract@@Int_map.findk.idselfwithNot_found->Noneletaddkvself:map=Int_map.addk.id(k.injectv)selftype'at={name:string;k:'akey;width:'a->int;pre:Out.t->inside:'aoption->'a->unit;post:Out.t->inside:'aoption->'a->unit;}letkey_counter_=ref0letmake(typea)?(width=fun_->0)~name~pre~post():at=letmoduleM=structtypeview+=Vofaendinletk={id=!key_counter_;inject=(funx->M.Vx);extract=(function|M.Vx->Somex|_->None);}inincrkey_counter_;{name;k;width;pre;post}endtypet={view:view;(** Document view *)wfl:int;(** Width if flattened *)}andview=|Nil|Newlineofint|Nestofint*t|Appendoft*t|Charofchar|Textofstring|Text_subofstring*int*int|Text_zero_widthofstring|Groupoft|Fillof{sep:t;l:tlist;}|Wrap:'aExt.t*'a*t->view(* debug printer *)letrecdebugout(self:t):unit=matchself.viewwith|Nil->Format.fprintfout"nil"|Newline1->Format.fprintfout"nl"|Newlinei->Format.fprintfout"nl(%d)"i|Nest(i,x)->Format.fprintfout"(@[nest %d@ %a@])"idebugx|Append(a,b)->Format.fprintfout"@[%a ^@ %a@]"debugadebugb|Charc->Format.fprintfout"%C"c|Texts->Format.fprintfout"%S"s|Text_zero_widths->Format.fprintfout"(zw %S)"s|Text_sub(s,i,len)->Format.fprintfout"%S"(String.subsilen)|Groupd->Format.fprintfout"(@[group@ %a@])"debugd|Fill{sep=_;l}->Format.fprintfout"(@[fill@ %a@])"(Format.pp_print_listdebug)l|Wrap(e,_,d)->Format.fprintfout"(@[ext.%s@ %a@])"e.namedebugdletnil:t={view=Nil;wfl=0}letnewline:t={view=Newline1;wfl=1}letnewline_or_spacesn:t=ifn<0theninvalid_arg"Containers_pp.newline_or_spaces";{view=Newlinen;wfl=n}letnl=newlineletcharc=ifc='\n'thennlelse{view=Charc;wfl=1}letnestix:t=matchx.viewwith|_wheni<=0->x|Nil->nil|_->{view=Nest(i,x);wfl=x.wfl}letappendab:t=matcha.view,b.viewwith|Nil,_->b|_,Nil->a|_->{view=Append(a,b);wfl=a.wfl+b.wfl}letgroupd:t=matchd.viewwith|Nil->nil|Group_->d|_->{view=Groupd;wfl=d.wfl}letext(ext:_Ext.t)vd:t=letwfl=d.wfl+ext.widthvin{view=Wrap(ext,v,d);wfl}let(^)=appendlettext_sub_silen:t={view=Text_sub(s,i,len);wfl=len}(* Turn [str], which contains some newlines, into a document.
We make a concatenation of
each line's content followed by a newline.
Then we group the result so that it remains in a unified block. *)letsplit_text_(str:string):t=letcur=refnilinleti=ref0inletlen=String.lengthstrinwhile!i<lendomatchString.index_fromstr!i'\n'with|exceptionNot_found->(* last chunk *)if!i+1<lenthencur:=!cur^text_sub_str!i(len-!i);i:=len|j->cur:=!cur^text_sub_str!i(j-!i)^nl;i:=j+1done;!curlettext(str:string):t=ifstr=""thennilelseifString.containsstr'\n'thensplit_text_strelse{view=Textstr;wfl=String.lengthstr}lettextpffmt=Printf.ksprintftextfmtlettextffmt=Format.kasprintftextfmtmoduleFlatten=structletto_out(out:Out.t)(self:t):unit=letrecloop(ext_map:Ext.map)(d:t)=matchd.viewwith|Nil|Newline0->()|Charc->out.charc|Newline1->out.char' '|Newlinen->for_i=1tondoout.char' 'done|Nest(_,x)->loopext_mapx|Append(x,y)->loopext_mapx;loopext_mapy|Texts|Text_zero_widths->out.strings|Text_sub(s,i,len)->out.sub_stringsilen|Groupx->loopext_mapx|Fill{sep;l}->List.iteri(funix->ifi>0thenloopext_mapsep;loopext_mapx)l|Wrap(ext,v,d)->letinside=Ext.getext.kext_mapinext.preout~insidev;letext_map'=Ext.addext.kvext_mapinloopext_map'd;ext.postout~insidevinloopExt.emptyselfletto_bufferbuf(self:t):unit=letout=Out.of_bufferbufinto_outoutselfletto_stringself:string=letbuf=Buffer.create32into_bufferbufself;Buffer.contentsbufendmodulePretty=structtypest={out:Out.t;width:int;ext_map:Ext.map;}(** Add [i] spaces of indentation. *)letadd_indentst(i:int)=for_i=1toidost.out.char' 'doneletrecpp_flatten(st:st)(self:t):int=matchself.viewwith|Nil|Newline0->0|Charc->st.out.charc;1|Newlinen->for_i=1tondost.out.char' 'done;n|Nest(_i,x)->pp_flattenstx|Append(x,y)->letn=pp_flattenstxinn+pp_flattensty|Texts->st.out.strings;String.lengths|Text_zero_widths->st.out.strings;0|Text_sub(s,i,len)->st.out.sub_stringsilen;len|Groupx->pp_flattenstx|Fill{sep;l}->(* print separated by spaces *)letn=ref0inList.iteri(funix->ifi>0thenn:=!n+pp_flattenstsep;n:=!n+pp_flattenstx)l;!n|Wrap(ext,v,d)->letinside=Ext.getext.kst.ext_mapinext.prest.out~insidev;letst'={stwithext_map=Ext.addext.kvst.ext_map}inletn=pp_flattenst'dinext.postst.out~insidev;n(** Does [x] fit in the current line when flattened, given that [k] chars
are already on the line? *)let[@inline]fits_flattenedstkx=x.wfl<=st.width-kletpp_newline(st:st)i=st.out.char'\n';add_indentsti(** Print [self] into the buffer.
@param k how many chars are already printed on the current line
*)letrecpp_rec(st:st)(k:int)(stack:(int*t)list):unit=matchstackwith|[]->()|(i,d)::stack_tl->pp_rec_topst~k~id(funstk->pp_recstkstack_tl)(** Print [d] at indentation [i], with [k] chars already printed
on the current line, then calls [kont] with the
new [k]. *)andpp_rec_topst~k~id(kont:st->int->unit):unit=matchd.viewwith|Nil->kontstk|Charc->st.out.charc;kontst(k+1)|Newline_->pp_newlinesti;kontsti|Nest(j,x)->pp_rec_topst~k~i:(i+j)xkont|Append(x,y)->(* print [x], then print [y] *)pp_rec_topst~k~ix(funstk->pp_rec_topst~k~iykont)|Texts->st.out.strings;kontst(k+String.lengths)|Text_zero_widths->st.out.strings;kontstk|Text_sub(s,i,len)->st.out.sub_stringsilen;kontst(k+len)|Groupx->iffits_flattenedstkxthen((* print flattened *)letw_x=pp_flattenstxinassert(w_x=x.wfl);kontst(k+w_x))elsepp_rec_topst~k~ixkont|Fill{sep;l}->pp_fillst~k~iseplkont|Wrap(ext,v,d)->letold_ext_map=st.ext_mapinletinside=Ext.getext.kst.ext_mapinext.prest.out~insidev;letst'={stwithext_map=Ext.addext.kvst.ext_map}inpp_rec_topst'~k~id(funstk->ext.postst.out~insidev;kont{stwithext_map=old_ext_map}k)andpp_fillst~k~isepl(kont:st->int->unit):unit=(* [k] is the current offset in the line *)letrecloopstidxkl=matchlwith|x::tl->iffits_flattenedstkxthen((* all flattened *)letw_sep=ifidx=0then0elsepp_flattenstsepinletw_x=pp_flattenstxinassert(w_x=x.wfl);loopst(idx+1)(k+w_x+w_sep)tl)else((* print, followed by a newline and resume filling with [k=i] *)letpp_and_continuestk=pp_rec_topst~k~ix(funstk->loopst(idx+1)ktl)inifidx>0then(* separator, then item *)pp_rec_topst~k~iseppp_and_continueelsepp_and_continuestk)|[]->kontstkinloopst0klletto_out~widthout(self:t):unit=letst={out;width;ext_map=Ext.empty}inpp_recst0[0,self]letto_buffer~width(buf:Buffer.t)(self:t):unit=to_out~width(Out.of_bufferbuf)selfletto_string~width(self:t):string=letbuf=Buffer.create32into_buffer~widthbufself;Buffer.contentsbufletto_format~widthoutself:unit=(* TODO: more efficient implementation based on out *)CCFormat.string_linesout(to_string~widthself)endletpp=Pretty.to_format~width:80(* helpers *)letsp=char' 'moduleInfix=structlet(^)=appendlet[@inline](^+)xy=x^sp^ylet[@inline](^/)xy=x^nl^yendincludeInfixlettrue_=text"true"letfalse_=text"false"letboolb=ifbthentrue_elsefalse_letintx:t=text(string_of_intx)letfloatx:t=text(string_of_floatx)letfloat_hexx:t=textpf"%h"xlettext_quoteds:t=text(Printf.sprintf"%S"s)lettext_zero_widths:t={view=Text_zero_widths;wfl=0}letappend_l?(sep=nil)l=letrecloop=function|[]->nil|[x]->x|x::tl->x^sep^looptlinlooplletappend_spl=append_l~sep:splletappend_nll=append_l~sep:nllletfillsep=function|[]->nil|[x]->x|l->(* flattened: just like concat *)letwfl=List.fold_left(funwflx->wfl+x.wfl)0l+((List.lengthl-1)*sep.wfl)in{view=Fill{sep;l};wfl}letfill_mapsepfl=fillsep(List.mapfl)letof_list?(sep=nil)fl=letrecloop=function|[]->nil|[x]->fx|x::tl->fx^sep^looptlinlooplletof_seq?(sep=nil)fseq:t=letrecloopfirstseq=matchseq()with|Seq.Nil->nil|Seq.Cons(x,tl)->letx=fxin(iffirstthenxelsesep^x)^loopfalsetlinlooptrueseqletbracketldr:t=group(textl^nest(String.lengthl)d^textr)letbracket2ldr:t=group(textl^nest2(nl^d)^nl^textr)letsexp_ll:t=char'('^nest1(group(append_nll^char')'))letsexp_applyal:t=sexp_l(texta::l)letsurround?(width=1)lbr=group(l^nestwidthb^r)moduleChar=structletbang=char'!'letat=char'@'lethash=char'#'letdollar=char'$'lettilde=char'~'letbackquote=char'`'letpercent=char'%'letcaret=char'^'letampersand=char'&'letstar=char'*'letminus=char'-'letunderscore=char'_'letplus=char'+'letequal=char'='letpipe=char'|'letslash=char'/'letbackslash=char'\\'letcolon=char':'letsemi=char';'letguillemet=char'"'letquote=char'\''letcomma=char','letdot=char'.'letquestion=char'?'letlparen=char'('letrparen=char')'letlbrace=char'{'letrbrace=char'}'letlbracket=char'['letrbracket=char']'letlangle=char'<'letrangle=char'>'endmoduleDump=structletlistl:t=letsep=char';'^nlingroup(char'['^nest1(fillsepl)^char']')letparensd=surroundChar.lparendChar.rparenletbracesd=surroundChar.lbracedChar.rbraceletbracketsd=surroundChar.lbracketdChar.rbracketletanglesd=surroundChar.langledChar.rangleletof_iter?(sep=nil)git=letr=refnilinit(funelt->r:=!r^sep^gelt);!rletof_array?(sep=nil)garr=letr=refnilinfori=0toArray.lengtharr-1dor:=!r^sep^garr.(i)done;!rendmoduleTerm_color=structtypecolor=[`Black|`Red|`Yellow|`Green|`Blue|`Magenta|`Cyan|`White]typestyle=[`FGofcolor(* foreground *)|`BGofcolor(* background *)|`Bold|`Reset|`Underline]letint_of_color_=function|`Black->0|`Red->1|`Green->2|`Yellow->3|`Blue->4|`Magenta->5|`Cyan->6|`White->7letcode_of_style:style->int=function|`FGc->30+int_of_color_c|`BGc->40+int_of_color_c|`Bold->1|`Reset->0|`Underline->4letspf=Printf.sprintfletstring_of_stylea=spf"\x1b[%dm"(code_of_stylea)letreset=string_of_style`Resetletstring_of_style_list=function|[]->reset|[a]->string_of_stylea|[a;b]->spf"\x1b[%d;%dm"(code_of_stylea)(code_of_styleb)|[a;b;c]->spf"\x1b[%d;%d;%dm"(code_of_stylea)(code_of_styleb)(code_of_stylec)|l->letbuf=Buffer.create32inletpp_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.contentsbufletext_style_:stylelistExt.t=Ext.make~name:"termcolor"~pre:(funout~inside:_l->Out.stringout(string_of_style_listl))~post:(funout~inside_l->letstyle=CCOption.map_or~default:resetstring_of_style_listinsideinOut.stringoutstyle)()(** Set the foreground color. *)letcolor(c:color)(d:t):t=extext_style_[`FGc]d(** Set a full style for this document. *)letstyle_l(l:stylelist)(d:t):t=extext_style_ldend