Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file tree.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394(*
* Copyright (c) 2016 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.
*)moduleHtml=Tyxml.HtmlmodulePaths=Odoc_model.PathsopenOdoc_model.Namestypesyntax=OCaml|Reasontypekind=[`Arg|`Mod|`Mty|`Class|`Cty|`Page]letstring_of_syntax=function|OCaml->"ml"|Reason->"re"typeuri=|Absoluteofstring|Relativeofstringtypet={name:string;content:[`Html]Html.elt;children:tlist}letpath=Stack.create()letstack_to_lists=letacc=ref[]inStack.iter(funx->acc:=x::!acc)s;!accletenter?kindname=Stack.push(name,kind)pathletleave()=ignore@@Stack.poppath(* FIXME: reuse [Url.kind] *)letstack_elt_to_path_fragment=function|(name,None)|(name,Some`Page)->name(* fixme? *)|(name,Some`Mod)->name|(name,Some`Mty)->"module-type-"^name|(name,Some`Arg)->"argument-"^name|(name,Some`Class)->"class-"^name|(name,Some`Cty)->"class-type-"^namemoduleRelative_link=structopenOdoc_model.Pathsletsemantic_uris=reffalsemoduleId:sigexceptionNot_linkableexceptionCan't_stop_beforevalhref:?xref_base_uri:string->stop_before:bool->Identifier.t->stringend=structexceptionNot_linkableletrecdrop_shared_prefixl1l2=matchl1,l2with|l1::l1s,l2::l2swhenl1=l2->drop_shared_prefixl1sl2s|_,_->l1,l2exceptionCan't_stop_beforelethref?xref_base_uri~stop_beforeid=matchxref_base_uri,Url.from_identifier~stop_beforeidwith(* If xref_base_uri is defined, do not perform relative URI resolution. *)|Somexref_base_uri,Ok{Url.page;anchor;kind}->letabsolute_target=List.rev(if!semantic_uris||kind="page"thenpageelse"index.html"::page)inletpage=xref_base_uri^String.concat"/"absolute_targetinbeginmatchanchorwith|""->page|anchor->page^"#"^anchorend|None,Ok{Url.page;anchor;kind}->lettarget=List.rev(if!semantic_uris||kind="page"thenpageelse"index.html"::page)inletcurrent_loc=letpath=matchStack.toppathwith|(_,Some`Page)->(* Sadness. *)lets=Stack.copypathinignore(Stack.pops);s|_->pathinList.mapstack_elt_to_path_fragment(stack_to_listpath)inletcurrent_from_common_ancestor,target_from_common_ancestor=drop_shared_prefixcurrent_loctargetinletrelative_target=List.map(fun_->"..")current_from_common_ancestor@target_from_common_ancestorinletpage=String.concat"/"relative_targetinbeginmatchanchorwith|""->page|anchor->page^"#"^anchorend|_,Errore->(* TODO: handle errors better, perhaps by returning a [result] *)matchewith|Not_linkable_->raiseNot_linkable|otherwise->Printf.eprintf"%s\n%!"(Url.Error.to_stringotherwise);exit1endmoduleOf_path=structletrecto_html:stop_before:bool->Path.t->_=fun~stop_beforepath->matchpathwith|`Rootroot->[Html.txtroot]|`Forwardroot->[Html.txtroot](* FIXME *)|`Dot(prefix,suffix)->letlink=to_html~stop_before:true(prefix:>Path.t)inlink@[Html.txt("."^suffix)]|`Apply(p1,p2)->letlink1=to_html~stop_before(p1:>Path.t)inletlink2=to_html~stop_before(p2:>Path.t)inlink1@Html.txt"("::link2@[Html.txt")"]|`Resolvedrp->letid=Path.Resolved.identifierrpinlettxt=Url.render_pathpathinbeginmatchId.href~stop_beforeidwith|href->[Html.a~a:[Html.a_hrefhref][Html.txttxt]]|exceptionId.Not_linkable->[Html.txttxt]|exceptionexn->Printf.eprintf"Id.href failed: %S\n%!"(Printexc.to_stringexn);[Html.txttxt]endendmoduleOf_fragment=structletdotprefixsuffix=matchprefixwith|""->suffix|_->prefix^"."^suffixletrecrender_raw:Fragment.t->string=funfragment->matchfragmentwith|`Resolvedrr->render_resolvedrr|`Dot(prefix,suffix)->dot(render_raw(prefix:>Fragment.t))suffixandrender_resolved:Fragment.Resolved.t->string=letopenFragment.Resolvedinfunfragment->matchfragmentwith|`Root->""|`Subst(_,rr)->render_resolved(rr:>t)|`SubstAlias(_,rr)->render_resolved(rr:>t)|`Module(rr,s)->dot(render_resolved(rr:>t))(ModuleName.to_strings)|`Type(rr,s)->dot(render_resolved(rr:>t))(TypeName.to_strings)|`Class(rr,s)->dot(render_resolved(rr:>t))(ClassName.to_strings)|`ClassType(rr,s)->dot(render_resolved(rr:>t))(ClassTypeName.to_strings)letrecto_html:stop_before:bool->Identifier.Signature.t->Fragment.t->_=fun~stop_beforeidfragment->letopenFragmentinmatchfragmentwith|`Resolved`Root->beginmatchId.href~stop_before:true(id:>Identifier.t)with|href->[Html.a~a:[Html.a_hrefhref][Html.txt(Identifier.nameid)]]|exceptionId.Not_linkable->[Html.txt(Identifier.nameid)]|exceptionexn->Printf.eprintf"[FRAG] Id.href failed: %S\n%!"(Printexc.to_stringexn);[Html.txt(Identifier.nameid)]end|`Resolvedrr->letid=Resolved.identifierid(rr:>Resolved.t)inlettxt=render_resolvedrrinbeginmatchId.href~stop_beforeidwith|href->[Html.a~a:[Html.a_hrefhref][Html.txttxt]]|exceptionId.Not_linkable->[Html.txttxt]|exceptionexn->Printf.eprintf"[FRAG] Id.href failed: %S\n%!"(Printexc.to_stringexn);[Html.txttxt]end|`Dot(prefix,suffix)->letlink=to_html~stop_before:trueid(prefix:>Fragment.t)inlink@[Html.txt("."^suffix)]endletof_path~stop_beforep=Of_path.to_html~stop_beforepletof_fragment~basefrag=Of_fragment.to_html~stop_before:falsebasefragletto_sub_element~kindname=(* FIXME: Reuse [Url]. *)letprefix=matchkindwith|`Mod->""|`Mty->"module-type-"|`Arg->"argument-"|`Class->"class-"|`Cty->"class-type-"|`Page->assertfalseinHtml.a_href(prefix^name^(if!semantic_uristhen""else"/index.html"))endletrender_fragment=Relative_link.Of_fragment.render_rawletpage_creator?kind?(theme_uri=Relative"./")~pathheader_docscontent=letrecadd_dotdot~nacc=ifn<=0thenaccelseadd_dotdot~n:(n-1)("../"^acc)inletresolve_relative_uriuri=(* Remove the first "dot segment". *)leturi=ifString.lengthuri>=2&&String.suburi02="./"thenString.suburi2(String.lengthuri-2)elseuriin(* How deep is this page? *)letn=List.lengthpath-((* This is just horrible. *)matchkindwith|Some`Page->1|_->0)inadd_dotdoturi~ninletname=List.hd@@List.revpathinlethead:Html_types.headHtml.elt=lettitle_string=Printf.sprintf"%s (%s)"name(String.concat"."path)inlettheme_uri=matchtheme_uriwith|Absoluteuri->uri|Relativeuri->resolve_relative_uriuriinletsupport_files_uri=resolve_relative_uri"./"inletodoc_css_uri=theme_uri^"odoc.css"inlethighlight_js_uri=support_files_uri^"highlight.pack.js"inHtml.head(Html.title(Html.txttitle_string))[Html.link~rel:[`Stylesheet]~href:odoc_css_uri();Html.meta~a:[Html.a_charset"utf-8"]();Html.meta~a:[Html.a_name"generator";Html.a_content"odoc 1.5.3"]();Html.meta~a:[Html.a_name"viewport";Html.a_content"width=device-width,initial-scale=1.0";]();Html.script~a:[Html.a_srchighlight_js_uri](Html.txt"");Html.script(Html.txt"hljs.initHighlightingOnLoad();");]inletwrapped_content:(Html_types.div_contentHtml.elt)list=lettitle_prefix=matchkindwith|None|Some`Mod->Some"Module"|Some`Arg->Some"Parameter"|Some`Mty->Some"Module type"|Some`Cty->Some"Class type"|Some`Class->Some"Class"|Some`Page->Noneinletheader_docs=matchtitle_prefixwith|None->header_docs|Someprefix->lettitle_heading=Html.h1[Html.txt@@prefix^" ";Html.code[(* Shorten path to at most 2 levels *)matchList.tlpath|>List.revwith|y::x::_->Html.txt@@x^"."^y|x::_->Html.txtx|_->Html.txt""(* error *)]]intitle_heading::header_docsinletheader_content=letdot=if!Relative_link.semantic_uristhen""else"index.html"inletdotdot=add_dotdot~n:1dotinletup_href=matchkindwith|Some`Pagewhenname<>"index"->dot|_->dotdotinlethas_parent=List.lengthpath>1inifhas_parentthenletnav=Html.nav@@[Html.a~a:[Html.a_hrefup_href][Html.txt"Up"];Html.txt" – "]@(* Create breadcrumbs *)letspace=Html.txt" "inletbreadcrumb_spec=matchkindwith|Some`Page->(funnx->n,dot,x)|_->(funnx->n,add_dotdot~ndot,x)inletrev_path=matchkindwith|Some`Pagewhenname="index"->List.tl(List.revpath)|_->List.revpathinrev_path|>List.mapibreadcrumb_spec|>List.rev|>Utils.list_concat_map?sep:(Some([space;Html.entity"#x00BB";space]))~f:(fun(n,addr,lbl)->ifn>0then[[Html.a~a:[Html.a_hrefaddr][Html.txtlbl]]]else[[Html.txtlbl]])|>List.flatteninnav::header_docselseheader_docsinletheader=Html.headerheader_contentin[Html.div~a:[Html.a_class["content"]](header::content)]inlethtml:[`Html]Html.elt=Html.htmlhead(Html.bodywrapped_content)inhtmlletmake?(header_docs=[])?theme_uricontentchildren=assert(not(Stack.is_emptypath));letname=stack_elt_to_path_fragment(Stack.toppath)inletkind=snd(Stack.toppath)inletpath=List.mapfst(stack_to_listpath)inletcontent=page_creator?kind?theme_uri~pathheader_docscontentin{name;content;children}lettraverse~ft=letrecauxparentsnode=f~parentsnode.namenode.content;List.iter(aux(node.name::parents))node.childreninaux[]tletopen_details=reftrue