123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123moduleStyle=structtypet=|Loc|Error|Warning|Kwd|Id|Prompt|Details|Ok|Debug|Success|Ansi_stylesofAnsi_color.Style.tlistendmodulePrint_config=structtypet=Style.t->Ansi_color.Style.tlistopenAnsi_color.Styleletdefault:Style.t->_=function|Loc->[bold]|Error->[bold;fg_red]|Warning->[bold;fg_magenta]|Kwd->[bold;fg_blue]|Id->[bold;fg_yellow]|Prompt->[bold;fg_green]|Details->[dim;fg_white]|Ok->[dim;fg_green]|Debug->[underlined;fg_bright_cyan]|Success->[bold;fg_green]|Ansi_stylesl->lendtypet={loc:Loc0.toption;paragraphs:Style.tPp.tlist;hints:Style.tPp.tlist}letmake?loc?prefix?(hints=[])paragraphs=letparagraphs=matchprefix,paragraphswith|None,l->l|Somep,[]->[p]|Somep,x::l->Pp.concat~sep:Pp.space[p;x]::lin{loc;hints;paragraphs}letpp{loc;paragraphs;hints}=letparagraphs=matchhintswith|[]->paragraphs|_->List.appendparagraphs(List.maphints~f:(funhint->Pp.concat~sep:Pp.space[Pp.verbatim"Hint:";hint]))inletparagraphs=List.mapparagraphs~f:Pp.boxinletparagraphs=matchlocwith|None->paragraphs|Some{Loc0.start;stop}->letstart_c=start.pos_cnum-start.pos_bolinletstop_c=stop.pos_cnum-start.pos_bolinPp.tag~tag:Style.Loc(Pp.textf"File %S, line %d, characters %d-%d:"start.pos_fnamestart.pos_lnumstart_cstop_c)::paragraphsinPp.vbox(Pp.concat_mapparagraphs~sep:Pp.nop~f:(funpp->Pp.seqppPp.cut))letprint?(config=Print_config.default)t=Ansi_color.print(Pp.map_tags(ppt)~f:config)letprerr?(config=Print_config.default)t=Ansi_color.prerr(Pp.map_tags(ppt)~f:config)(* As found here http://rosettacode.org/wiki/Levenshtein_distance#OCaml *)letlevenshtein_distancest=letm=String.lengthsandn=String.lengthtin(* for all i and j, d.(i).(j) will hold the Levenshtein distance between
the first i characters of s and the first j characters of t *)letd=Array.make_matrix~dimx:(m+1)~dimy:(n+1)0infori=0tomdo(* the distance of any first string to an empty second string *)d.(i).(0)<-idone;forj=0tondo(* the distance of any second string to an empty first string *)d.(0).(j)<-jdone;forj=1tondofori=1tomdoifs.[i-1]=t.[j-1]thend.(i).(j)<-d.(i-1).(j-1)(* no operation required *)elsed.(i).(j)<-min(d.(i-1).(j)+1)(* a deletion *)(min(d.(i).(j-1)+1)(* an insertion *)(d.(i-1).(j-1)+1)(* a substitution *))done;done;d.(m).(n)letdid_you_means~candidates=letcandidates=List.filtercandidates~f:(funcandidate->levenshtein_distancescandidate<3)inmatchcandidateswith|[]->[]|l->[Pp.textf"did you mean %s?"(String.enumerate_orl)]