123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379(*
* Copyright (c) 2016, 2017 Thomas Refis <trefis@janestreet.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openTypesmoduleComment=Odoc_model.CommentopenOdoc_model.Namesletdefault_lang_tag="ocaml"letsource_of_codes=ifs=""then[]else[Source.Elt[inline@@Inline.Texts]]moduleReference=structopenOdoc_model.Pathsletrecrender_resolved:Reference.Resolved.t->string=funr->letopenReference.Resolvedinmatchrwith|`Identifierid->Identifier.nameid|`Alias(_,r)->render_resolved(r:>t)|`AliasModuleType(_,r)->render_resolved(r:>t)|`Module(r,s)->render_resolved(r:>t)^"."^ModuleName.to_strings|`Hiddenp->render_resolved(p:>t)|`ModuleType(r,s)->render_resolved(r:>t)^"."^ModuleTypeName.to_strings|`Type(r,s)->render_resolved(r:>t)^"."^TypeName.to_strings|`Constructor(r,s)->render_resolved(r:>t)^"."^ConstructorName.to_strings|`Field(r,s)->render_resolved(r:>t)^"."^FieldName.to_strings|`Extension(r,s)->render_resolved(r:>t)^"."^ExtensionName.to_strings|`ExtensionDecl(r,_,s)->render_resolved(r:>t)^"."^ExtensionName.to_strings|`Exception(r,s)->render_resolved(r:>t)^"."^ExceptionName.to_strings|`Value(r,s)->render_resolved(r:>t)^"."^ValueName.to_strings|`Class(r,s)->render_resolved(r:>t)^"."^ClassName.to_strings|`ClassType(r,s)->render_resolved(r:>t)^"."^ClassTypeName.to_strings|`Method(r,s)->(* CR trefis: do we really want to print anything more than [s] here? *)render_resolved(r:>t)^"."^MethodName.to_strings|`InstanceVariable(r,s)->(* CR trefis: the following makes no sense to me... *)render_resolved(r:>t)^"."^InstanceVariableName.to_strings|`Label(_,s)->LabelName.to_stringsletrecrender_unresolved:Reference.t->string=letopenReferenceinfunction|`Resolvedr->render_resolvedr|`Root(n,_)->n|`Dot(p,f)->render_unresolved(p:>t)^"."^f|`Module(p,f)->render_unresolved(p:>t)^"."^ModuleName.to_stringf|`ModuleType(p,f)->render_unresolved(p:>t)^"."^ModuleTypeName.to_stringf|`Type(p,f)->render_unresolved(p:>t)^"."^TypeName.to_stringf|`Constructor(p,f)->render_unresolved(p:>t)^"."^ConstructorName.to_stringf|`Field(p,f)->render_unresolved(p:>t)^"."^FieldName.to_stringf|`Extension(p,f)->render_unresolved(p:>t)^"."^ExtensionName.to_stringf|`ExtensionDecl(p,f)->render_unresolved(p:>t)^"."^ExtensionName.to_stringf|`Exception(p,f)->render_unresolved(p:>t)^"."^ExceptionName.to_stringf|`Value(p,f)->render_unresolved(p:>t)^"."^ValueName.to_stringf|`Class(p,f)->render_unresolved(p:>t)^"."^ClassName.to_stringf|`ClassType(p,f)->render_unresolved(p:>t)^"."^ClassTypeName.to_stringf|`Method(p,f)->render_unresolved(p:>t)^"."^MethodName.to_stringf|`InstanceVariable(p,f)->render_unresolved(p:>t)^"."^InstanceVariableName.to_stringf|`Label(p,f)->render_unresolved(p:>t)^"."^LabelName.to_stringf(* This is the entry point. *)letto_ir:?text:Inline.t->Reference.t->Inline.t=fun?textref->matchrefwith|`Resolvedr->((* IDENTIFIER MUST BE RENAMED TO DEFINITION. *)letid=Reference.Resolved.identifierrinletrendered=render_resolvedrinletcontent=matchtextwith|None->[inline@@Inline.Source(source_of_coderendered)]|Somes->sandtooltip=(* Add a tooltip if the content is not the rendered reference. *)matchtextwithNone->None|Some_->SomerenderedinmatchUrl.from_identifier~stop_before:falseidwith|Okurl->lettarget=InternalLink.Resolvedurlinletlink={InternalLink.target;content;tooltip}in[inline@@Inline.InternalLinklink]|Error(Not_linkable_)->content|Errorexn->(* FIXME: better error message *)Printf.eprintf"Id.href failed: %S\n%!"(Url.Error.to_stringexn);content)|_->(lets=render_unresolvedrefinmatchtextwith|None->lets=source_of_codesin[inline@@Inline.Sources]|Somecontent->letlink={InternalLink.target=Unresolved;content;tooltip=Somes}in[inline@@Inline.InternalLinklink])endletleaf_inline_element:Comment.leaf_inline_element->Inline.one=function|`Space->inline@@Text" "|`Words->inline@@Texts|`Code_spans->inline@@Source(source_of_codes)|`Math_spans->inline@@Maths|`Raw_markup(target,s)->inline@@Raw_markup(target,s)letrecnon_link_inline_element:Comment.non_link_inline_element->Inline.one=function|#Comment.leaf_inline_elementase->leaf_inline_elemente|`Styled(style,content)->inline@@Styled(style,non_link_inline_element_listcontent)andnon_link_inline_element_list:_->Inline.t=funelements->List.map(funelt->non_link_inline_elementelt.Odoc_model.Location_.value)elementsletlink_content=non_link_inline_element_listletrecinline_element:Comment.inline_element->Inline.t=function|#Comment.leaf_inline_elementase->[leaf_inline_elemente]|`Styled(style,content)->[inline@@Styled(style,inline_element_listcontent)]|`Reference(path,content)->(* TODO Rework that ugly function. *)(* TODO References should be set in code style, if they are to code
elements. *)letcontent=matchcontentwith|[]->None|_->Some(non_link_inline_element_listcontent)(* XXX Span *)inReference.to_ir?text:contentpath|`Link(target,content)->letcontent=matchcontentwith|[]->[inline@@Texttarget]|_->non_link_inline_element_listcontentin[inline@@Link(target,content)]andinline_element_listelements=List.concat@@List.map(funelt->inline_elementelt.Odoc_model.Location_.value)elementsletmodule_referencesms=letmodule_reference(m:Comment.module_reference)=letreference=Reference.to_ir(m.module_reference:>Odoc_model.Paths.Reference.t)andsynopsis=matchm.module_synopsiswith|Somesynopsis->[block~attr:["synopsis"]@@Inline(inline_element_listsynopsis);]|None->[]in{Description.attr=[];key=reference;definition=synopsis}inletitems=List.mapmodule_referencemsinblock~attr:["modules"]@@Descriptionitemsletrecnestable_block_element:Comment.nestable_block_element->Block.onelist=funcontent->matchcontentwith|`Paragraphp->[paragraphp]|`Code_block(lang_tag,code,outputs)->letlang_tag=matchlang_tagwithNone->default_lang_tag|Somet->tinletrest=matchoutputswith|Somexs->nestable_block_element_listxs|None->[]in[block@@Source(lang_tag,source_of_code(Odoc_model.Location_.valuecode));]@rest|`Math_blocks->[block@@Maths]|`Verbatims->[block@@Verbatims]|`Modulesms->[module_referencesms]|`List(kind,items)->letkind=matchkindwith|`Unordered->Block.Unordered|`Ordered->Block.Orderedinletf=function|[{Odoc_model.Location_.value=`Paragraphcontent;_}]->[block@@Block.Inline(inline_element_listcontent)]|item->nestable_block_element_listiteminletitems=List.mapfitemsin[block@@Block.List(kind,items)]|`Table{data;align}->letdata=List.map(List.map(fun(cell,cell_type)->(nestable_block_element_listcell,cell_type)))datainletgenerate_aligndata=letmax(a:int)b=ifa<bthenbelseain(* Length of the longest line of the table *)letmax_length=List.fold_left(funml->maxm(List.lengthl))0datainletreclist_initi=ifi<=0then[]elseTable.Default::list_init(i-1)inlist_initmax_lengthinletalign=matchalignwith|None->generate_aligndata|Somealign->List.map(function|None->Table.Default|Some`Right->Right|Some`Left->Left|Some`Center->Center)align(* We should also check wellness of number of table cells vs alignment,
and raise warnings *)in[block@@Table{data;align}]andparagraph:Comment.paragraph->Block.one=function|[{value=`Raw_markup(target,s);_}]->block@@Block.Raw_markup(target,s)|p->block@@Block.Paragraph(inline_element_listp)andnestable_block_element_list:Comment.nestable_block_elementComment.with_locationlist->Block.onelist=funelements->elements|>List.mapOdoc_model.Location_.value|>List.mapnestable_block_element|>List.concatlettag:Comment.tag->Description.one=funt->letsp=inline(Text" ")inletitem?value~tagdefinition=lettag_name=inline~attr:["at-tag"](Texttag)inlettag_value=matchvaluewithNone->[]|Somet->sp::tinletkey=tag_name::tag_valuein{Description.attr=[tag];key;definition}inletmk_valuedesc=[inline~attr:["value"]desc]inlettext_defs=[block(Block.Inline[inline@@Texts])]inletcontent_to_inline?(prefix=[])content=matchcontentwith|None->[]|Somecontent->prefix@[inline@@Textcontent]inmatchtwith|`Authors->item~tag:"author"(text_defs)|`Deprecatedcontent->item~tag:"deprecated"(nestable_block_element_listcontent)|`Param(name,content)->letvalue=mk_value(Inline.Textname)initem~tag:"parameter"~value(nestable_block_element_listcontent)|`Raise(kind,content)->letvalue=inline_element(kind:>Comment.inline_element)initem~tag:"raises"~value(nestable_block_element_listcontent)|`Returncontent->item~tag:"returns"(nestable_block_element_listcontent)|`See(kind,target,content)->letvalue=matchkindwith|`Url->mk_value(Inline.Link(target,[inline@@Texttarget]))|`File->mk_value(Inline.Source(source_of_codetarget))|`Document->mk_value(Inline.Texttarget)initem~tag:"see"~value(nestable_block_element_listcontent)|`Sinces->item~tag:"since"(text_defs)|`Before(version,content)->letvalue=mk_value(Inline.Textversion)initem~tag:"before"~value(nestable_block_element_listcontent)|`Versions->item~tag:"version"(text_defs)|`Alert("deprecated",content)->letcontent=content_to_inlinecontentinitem~tag:"deprecated"[block(Block.Inlinecontent)]|`Alert(tag,content)->letcontent=content_to_inline~prefix:[sp]contentinitem~tag:"alert"[block(Block.Inline([inline@@Texttag]@content))]letattached_block_element:Comment.attached_block_element->Block.t=function|#Comment.nestable_block_elementase->nestable_block_elemente|`Tagt->[block~attr:["at-tags"]@@Description[tagt]](* TODO collaesce tags *)letblock_element:Comment.block_element->Block.t=function|#Comment.attached_block_elementase->attached_block_elemente|`Heading(_,_,text)->(* We are not supposed to receive Heading in this context.
TODO: Remove heading in attached documentation in the model *)[block@@Paragraph(inline_element_listtext)]letheading_level_to_int=function|`Title->0|`Section->1|`Subsection->2|`Subsubsection->3|`Paragraph->4|`Subparagraph->5letheading(attrs,{Odoc_model.Paths.Identifier.iv=`Label(_,label);_},text)=letlabel=Odoc_model.Names.LabelName.to_stringlabelinlettitle=inline_element_listtextinletlevel=heading_level_to_intattrs.Comment.heading_levelinletlabel=Somelabelinletsource_anchor=NoneinItem.Heading{label;level;title;source_anchor}letitem_element:Comment.block_element->Item.tlist=function|#Comment.attached_block_elementase->[Item.Text(attached_block_elemente)]|`Headingh->[headingh](** The documentation of the expansion is used if there is no comment attached
to the declaration. *)letsynopsis~decl_doc~expansion_doc=let([],Somedocs|docs,_)=(decl_doc,expansion_doc)inmatchComment.synopsisdocswithSomep->[paragraphp]|None->[]letstandalonedocs=Utils.flatmap~f:item_element@@List.map(funx->x.Odoc_model.Location_.value)docsletto_ir(docs:Comment.docs)=Utils.flatmap~f:block_element@@List.map(funx->x.Odoc_model.Location_.value)docslethas_docdocs=docs<>[]