Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file Fmt_odoc.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293(**************************************************************************)(* *)(* OCamlFormat *)(* *)(* Copyright (c) Facebook, Inc. and its affiliates. *)(* *)(* This source code is licensed under the MIT license found in *)(* the LICENSE file in the root directory of this source tree. *)(* *)(**************************************************************************)openFmtopenOdoc_parser.AstmoduleLoc=Odoc_parser.Loctypeconf={fmt_code:Fmt.code_formatter}(** Escape characters if they are not already escaped. [escapeworthy] should
be [true] if the character should be escaped, [false] otherwise. *)letensure_escape?(escape_char='\\')~escapeworthys=letdst=Buffer.create(String.lengths+8)inletprev_off=ref0inletstashuntil=Buffer.add_substringdsts~pos:!prev_off~len:(until-!prev_off)inletlen=String.lengthsinfori=0tolen-1doifescapeworthys.[i]&¬(String.Escaping.is_char_escapeds~escape_chari)then(stashi;prev_off:=i;Buffer.add_chardstescape_char)done;stashlen;Buffer.contentsdstletescape_bracketss=letescapeworthy=function'['|']'->true|_->falseinensure_escape~escapeworthysletescape_alls=letescapeworthy=function|'@'|'{'|'}'|'['|']'->true|_->falseinensure_escape~escapeworthysletsplit_on_whitespaces=String.split_on_chars~on:['\t';'\n';'\011';'\012';'\r';' '](** Escape special characters and normalize whitespaces *)letstr_normalized?(escape=escape_all)s=split_on_whitespacess|>List.filter~f:(Fn.nonString.is_empty)|>funs->lists"@ "(funs->escapes|>str)letign_loc~fwith_loc=fwith_loc.Loc.valueletfmt_verbatim_blocks=letforce_break=String.containss'\n'inletcontent=(* Literal newline to avoid indentation *)ifforce_breakthenwrap"\n""@\n"(strs)elsefits_breaks" ""\n"$strs$fits_breaks" "~hint:(0,0)""inhvbox0(wrap"{v""v}"content)letfmt_metadata(lang,meta)=letfmt_metameta=str" "$strmetainstr"@"$ign_loc~f:strlang$optmeta(ign_loc~f:fmt_meta)letfmt_code_blockconfs1s2=letwrap_codex=str"{"$opts1fmt_metadata$fmt"[@;<1000 2>"$x$fmt"@ ]}"inletfmt_line~first~last:_l=letl=String.rstripliniffirstthenstrlelseifString.lengthl=0thenstr"\n"elsefmt"@,"$strlinletfmt_no_codes=letlines=String.split_linessinletbox=matchlineswith_::_::_->vbox0|_->hvbox0inbox(wrap_code(vbox0(list_fllinesfmt_line)))inletOdoc_parser.Loc.{location;value}=s2inmatchs1with|Some({value="ocaml";_},_)|None->(matchconf.fmt_codevaluewith|Okformatted->hvbox0(wrap_codeformatted)|Error(`Msgmessage)->(matchmessagewith|""->()|_->Docstring.warnCaml.Format.err_formatter{location;message=Format.sprintf"invalid code block: %s"message});fmt_no_codevalue)|Some_->fmt_no_codevalueletfmt_code_spans=hovbox0(wrap"[""]"(str(escape_bracketss)))letfmt_math_spans=hovbox2(wrap"{m ""}"(strs))letfmt_math_blocks=letlines=List.drop_while~f:String.is_empty@@List.rev@@List.drop_while~f:String.is_empty@@List.rev_map~f:String.strip@@String.split_linessinletfmt~first~last:_line=iffirstthenstrlineelseifString.is_emptylinethenstr"\n"elsefmt"@;<1000 0>"$strlineinhvbox2(wrap"{math@;""@;<0 -2>}"(list_fllinesfmt))letfmt_reference=ign_loc~f:str_normalized(* Decide between using light and heavy syntax for lists *)letlist_should_use_heavy_syntaxitems=letheavy_nestable_block_elements=function(* More than one element or contains a list *)|[{Loc.value=`List_;_}]|_::_::_->true|[]|[_]->falseinList.existsitems~f:heavy_nestable_block_elements(* Decide if should break between two elements *)letblock_element_should_breakelemnext=match(elem,next)with(* Mandatory breaks *)|`List(_,_,_),_|`Paragraph_,`Paragraph_->true(* Arbitrary breaks *)|(`Paragraph_|`Heading_),_|_,(`Paragraph_|`Heading_)->true|_,_->false(* Format a list of block_elements separated by newlines Inserts blank line
depending on [block_element_should_break] *)letlist_block_elemelemsf=list_pnelems(fun~prev:_elem~next->letelem=elem.Loc.valueinletbreak=matchnextwith|Some{Loc.value=n;_}whenblock_element_should_break(elem:>block_element)(n:>block_element)->fmt"\n@\n"|Some_->fmt"@\n"|None->noopinfelem$break)letspace_elt:inline_elementwith_location=Loc.(at(span[])(`Space""))letrecfmt_inline_elementselements=letwrap_elementsopncls~always_wraphd=function|[]->wrap_ifalways_wrapopnclshd|tl->wrapopncls(hd$fmt_inline_elements(space_elt::tl))inletrecaux=function|[]->noop|`Space_::`Wordw::t->(* Escape lines starting with '+' or '-' *)letescape=ifString.lengthw>0&&Char.(w.[0]='+'||w.[0]='-')then"\\"else""incbreak~fits:("",1,"")~breaks:("",0,escape)$str_normalizedw$auxt|`Space_::t->fmt"@ "$auxt|`Wordw::t->str_normalizedw$auxt|`Code_spans::t->fmt_code_spans$auxt|`Math_spans::t->fmt_math_spans$auxt|`Raw_markup(lang,s)::t->letlang=matchlangwith|Somel->str_normalizedl$str":"|None->noopinwrap"{%%""%%}"(lang$strs)$auxt|`Styled(style,elems)::t->lets=matchstylewith|`Bold->"b"|`Italic->"i"|`Emphasis->"e"|`Superscript->"^"|`Subscript->"_"inhovbox(1+String.lengths+1)(wrap_elements"{""}"~always_wrap:true(str_normalizeds)elems)$auxt|`Reference(_kind,rf,txt)::t->letrf=wrap"{!""}"(fmt_referencerf)inwrap_elements"{""}"~always_wrap:falserftxt$auxt|`Link(url,txt)::t->leturl=wrap"{:""}"(str_normalizedurl)inwrap_elements"{""}"~always_wrap:falseurltxt$auxtinaux(List.mapelements~f:(ign_loc~f:Fn.id))andfmt_nestable_block_elementc=function|`Paragraphelems->fmt_inline_elementselems|`Code_block(s1,s2)->fmt_code_blockcs1s2|`Math_blocks->fmt_math_blocks|`Verbatims->fmt_verbatim_blocks|`Modulesmods->hovbox0(wrap"{!modules:@,""@,}"(listmods"@ "(funref->fmt_referenceref)))|`List(k,_syntax,items)whenlist_should_use_heavy_syntaxitems->fmt_list_heavyckitems|`List(k,_syntax,items)->fmt_list_lightckitemsandfmt_list_heavyckinditems=letfmt_itemelems=letbox=matchelemswith[_]->hvbox3|_->vbox3inbox(wrap"{- ""@;<1 -3>}"(fmt_nestable_block_elementscelems))andstart:s=matchkindwith`Unordered->"{ul@,"|`Ordered->"{ol@,"invbox1(wrapstart"@;<1 -1>}"(listitems"@,"fmt_item))andfmt_list_lightckinditems=letline_start=matchkindwith`Unordered->fmt"- "|`Ordered->fmt"+ "inletfmt_itemelems=line_start$hovbox0(fmt_nestable_block_elementscelems)invbox0(listitems"@,"fmt_item)andfmt_nestable_block_elementscelems=list_block_elemelems(fmt_nestable_block_elementc)letat=char'@'letspace=fmt"@ "letfmt_tag_args?arg?txtctag=at$strtag$optarg(funx->char' '$x)$opttxt(function|[]->noop|x->space$hovbox0(fmt_nestable_block_elementscx))letwrap_see=function|`Url->wrap"<"">"|`File->wrap"'""'"|`Document->wrap"\"""\""letfmt_tagc=function|`Authors->fmt_tag_argsc"author"~arg:(strs)|`Versions->fmt_tag_argsc"version"~arg:(strs)|`See(k,sr,txt)->fmt_tag_argsc"see"~arg:(wrap_seek(strsr))~txt|`Sinces->fmt_tag_argsc"since"~arg:(strs)|`Before(s,txt)->fmt_tag_argsc"before"~arg:(strs)~txt|`Deprecatedtxt->fmt_tag_argsc"deprecated"~txt|`Param(s,txt)->fmt_tag_argsc"param"~arg:(strs)~txt|`Raise(s,txt)->fmt_tag_argsc"raise"~arg:(strs)~txt|`Returntxt->fmt_tag_argsc"return"~txt|`Inline->fmt_tag_argsc"inline"|`Open->fmt_tag_argsc"open"|`Closed->fmt_tag_argsc"closed"|`Canonicalref->fmt_tag_argsc"canonical"~arg:(fmt_referenceref)letfmt_block_elementc=function|`Tagtag->hovbox2(fmt_tagctag)|`Heading(lvl,lbl,elems)->letlvl=Int.to_stringlvlinletlbl=matchlblwith|Somelbl->str":"$str_normalizedlbl|None->noopinletelems=ifList.is_emptyelemsthenelemselsespace_elt::elemsinhovbox0(wrap"{""}"(strlvl$lbl$fmt_inline_elementselems))|#nestable_block_elementaselm->hovbox0(fmt_nestable_block_elementcelm)letfmt~fmt_code(docs:t)=vbox0(list_block_elemdocs(fmt_block_element{fmt_code}))