123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106(*
* Copyright (c) 2022 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* 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.
*)openOmdopenAstringletsrc=Logs.Src.create"irmin.tree"~doc:"Persistent lazy trees for Irmin"moduleLog=(valLogs.src_logsrc:Logs.LOG)letpp=Fmt.of_to_stringOmd.to_sexptypetoken=Toc|Begin|Endlettextt=Text([],t)lethtmlt=Html_block([],t)letconcatts=Concat([],List.maptextts)lettoc=concat["[";"toc";"]"]letbegin_toc="<div class=\"toc\">"letend_toc="</div>"(* [toc] is either:
- empty; in that case it appears as [toc] in the Markdown file
- expanded: in that case it appears between `[//]: # begin toc` and
`[//]: # end toc` markers *)letis_toc=function|Paragraph(_,x)whenx=toc->SomeToc|Html_block(_,x)whenx=begin_toc->SomeBegin|Html_block(_,x)whenx=end_toc->SomeEnd|Html_block(_,x)whenx=begin_toc^"\n"->SomeBegin|Html_block(_,x)whenx=end_toc^"\n"->SomeEnd|_->Noneletrecreplace~toc:doc->doc=function|[]->[]|h::t->(matchis_tochwith|None->h::replace~toct|SomeToc->htmlbegin_toc::toc::htmlend_toc::replace~toct|SomeBegin->h::toc::skip_to_end~toct|SomeEnd->failwith"malformed toc markers")andskip_to_end~toc:doc->doc=function|[]->[]|h::t->(matchis_tochwith|SomeEnd->h::replace~toct|_->skip_to_end~toct)moduleLinkify=struct(* Convert section title to a valid HTML ID. *)lettitle_to_ids=String.filter(func->Char.Ascii.is_alphanumc||c=' ')s|>String.map(function' '->'-'|c->c)letinline:'attrinline->'attrinline=funlabel->letid=Pp_markdown.to_string[Paragraph([],label)]inLink([],{label;destination="#"^title_to_idid;title=None})letrecblock:'attrblock->'attrblock=function|Paragraph(attr,x)->Paragraph(attr,inlinex)|List(attr,ty,sp,bl)->List(attr,ty,sp,List.map(List.mapblock)bl)|_->failwith"invalid mardkown in TOC"endtypet=attributesblockoptionletv?(depth=10)?(add_links=true)doc:t=matchOmd.toc~depth~start:[1]docwith|[]->None|[toc]->lettoc=ifadd_linksthenLinkify.blocktocelsetocinSometoc|_->assertfalse(* this is an invariant in Omd.toc *)letexpand?depthdoc=matchv?depthdocwith|None->None|Sometoc->Log.info(funl->l"TOC=%a"pp[toc]);Log.debug(funl->l"BEFORE: %a"ppdoc);letdoc=replace~tocdocinLog.debug(funl->l"AFTER: %a"ppdoc);Somedocletto_string=Pp_markdown.to_stringletppppf(t:t)=matchtwith|None->Fmt.pfppf"No sections."|Somet->Fmt.of_to_stringto_stringppf[t]