123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)(* <O___,, * (see CREDITS file for the list of authors) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(************************************************************************)(* Coq Language Server Protocol *)(* Copyright (C) 2019 MINES ParisTech -- Dual License LGPL 2.1 / GPL3+ *)(* Copyright (C) 2019-2022 Emilio J. Gallego Arias, INRIA *)(* Copyright (C) 2022-2022 Shachar Itzhaky, Technion *)(************************************************************************)moduletypePoint=sigtypetvalin_range:?range:Lang.Range.t->t->boolvalgt_range:?range:Lang.Range.t->t->booltypeoffset_table=stringvalto_offset:t->offset_table->intvalto_string:t->stringendmoduleLineCol:Pointwithtypet=int*int=structtypet=int*inttypeoffset_table=stringletline_lengthoffsettext=matchString.index_from_opttextoffset'\n'with|Somel->l-offset|None->String.lengthtext-offsetletrecto_offsetcurlc(l,c)text=Io.Log.trace"to_offset"(Format.asprintf"cur: %d | lc: %d | l: %d c: %d"curlclc);iflc=lthencur+celseletll=line_lengthcurtext+1into_offset(cur+ll)(lc+1)(l,c)textletto_offset(l,c)text=to_offset00(l,c)textletto_string(l,c)="("^string_of_intl^","^string_of_intc^")"letdebug_in_range=falseletdebug_in_rangehdrlinecolline1col1line2col2=ifdebug_in_rangethenIo.Log.tracehdr(Format.asprintf"(%d, %d) in (%d,%d)-(%d,%d)"linecolline1col1line2col2)letin_range?range(line,col)=(* Coq starts at 1, lsp at 0 *)matchrangewith|None->false|Somer->letline1=r.Lang.Range.start.lineinletcol1=r.start.characterinletline2=r.end_.lineinletcol2=r.end_.characterindebug_in_range"in_range"linecolline1col1line2col2;(line1<line&&line<line2)||ifline1=line&&line2=linethencol1<=col&&col<col2else(line1=line&&col1<=col)||(line2=line&&col<col2)letgt_range?range(line,col)=matchrangewith|None->false|Somer->letline1=r.Lang.Range.start.lineinletcol1=r.start.characterinletline2=r.end_.lineinletcol2=r.end_.characterindebug_in_range"gt_range"linecolline1col1line2col2;line<line1||(line=line1&&col<col1)endmoduleOffset:Pointwithtypet=int=structtypet=inttypeoffset_table=stringletin_range?rangepoint=matchrangewith|None->false|Somerange->range.Lang.Range.start.offset<=point&&point<range.Lang.Range.end_.offsetletgt_range?rangepoint=matchrangewith|None->false|Somerange->point<range.Lang.Range.start.offsetletto_offsetoff_=offletto_stringoff=string_of_intoffendtypeapprox=|Exact(* Exact on point *)|PrevIfEmpty(* If no match, return prev *)|PrevmoduletypeS=sigmoduleP:Pointtype('a,'r)query=doc:Doc.t->point:P.t->'a->'roptionvalnode:(approx,Doc.Node.t)queryendletsomex=SomexmoduleMake(P:Point):SwithmoduleP:=P=structtype('a,'r)query=doc:Doc.t->point:P.t->'a->'roptionletfind~doc~pointapprox=letrecfindprevl=matchlwith|[]->prev|node::xs->(letrange=node.Doc.Node.rangeinmatchapproxwith|Exact->ifP.in_range~rangepointthenSomenodeelsefindNonexs|PrevIfEmpty->ifP.gt_range~rangepointthenprevelsefind(Somenode)xs|Prev->ifP.gt_range~rangepoint||P.in_range~rangepointthenprevelsefind(Somenode)xs)infindNonedoc.Doc.nodesletnode=findendmoduleLC=Make(LineCol)moduleO=Make(Offset)(* XXX: We need to split this module in two: one that handles the extraction of
information from a document, and the other that further processes it, like
for goals, possibly executing Coq code. *)(* Related to goal request *)moduleGoals=structletpr_goal~tokenst=letppxenvsigmax=let{Coq.Protect.E.r;feedback}=Coq.Print.pr_letype_env~token~goal_concl_style:trueenvsigmaxin(* XXX: We ideally want to thread this in the monad too, but it'd be
better if the printer was more functional *)Io.Log.feedbackfeedback;matchrwith|Coq.Protect.R.Completed(Okpr)->pr|Coq.Protect.R.Completed(Error_pr)->Pp.str"printer failed!"|Interrupted->Pp.str"printer interrupted!"inletlemmas=Coq.State.lemmas~stinOption.map(Coq.Goals.reify~ppx)lemmas(* We need to use [in_state] here due to printing not being pure, but we want
a better design here eventually *)letgoals~token~st=Coq.State.in_state~token~st~f:(pr_goal~token)stletprogram~st=Coq.State.program~stendmoduleCompletion=struct(* XXX: This belongs in Coq *)letpr_extrefgr=matchgrwith|Globnames.TrueGlobalgr->Printer.pr_globalgr|Globnames.Abbrevkn->Names.KerName.printkn(* XXX This may fail when passed "foo." for example, so more sanitizing is
needed *)letto_qualidp=trySome(Libnames.qualid_of_stringp)with_->Noneletcandidates~token~stprefix=let(let*)=Option.bindinCoq.State.in_state~token~stprefix~f:(funprefix->let*p=to_qualidprefixinNametab.completion_canditatesp|>List.map(funx->Pp.string_of_ppcmds(pr_extrefx))|>some)end