123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230openConstropenLibnamesopenNametabopenPrinteropenPpx_yojson_conv_lib.Yojson_conv.Primitives(** Builtin commands, options, tactics, and attributes *)(*
Some vernacular is implemented internally in Rocq and not visible as a normal definition
that could be added to a completion database through standard scraping. Same goes for
Ltac1 tactics, or attributes.
To remedy this, we scrape the official documentation of Rocq and create indices of all
of the built-in tactics, commands, options, and attributes. These indices are then loaded into
vsrocqtop to serve these completions to the user.
*)(* The grammar of the builtin item as defined in the official grammar *)typebuiltin_syntax=|Literalof{value:string;subscript:stringoption;}|Referenceof{value:string;subscript:stringoption;}|Alternativeof{children:builtin_syntaxlist;}|Repeatof{min:int;max:intoption;separator:stringoption;children:builtin_syntaxlist;}[@@derivingof_yojson](* Pretty print of the builtin syntax item *)letrecpp_builtin_syntax(syntax:builtin_syntax):string=matchsyntaxwith|Literal{value;subscript}->(matchsubscriptwith|Somesub->Printf.sprintf"%s_%s"valuesub|None->value)|Reference{value;subscript}->(matchsubscriptwith|Somesub->Printf.sprintf"%s_%s"valuesub|None->value)|Alternative{children}->String.concat"|"(List.mappp_builtin_syntaxchildren)|Repeat{min;max;separator;children}->letquant=match(min,max)with|(0,Some1)->"?"|(0,None)->"*"|(1,None)->"+"|(m,Somen)whenm=n->Printf.sprintf"{%d}"m|(m,Somen)->Printf.sprintf"{%d,%d}"mn|(m,None)->Printf.sprintf"{%d,}"minletsep=Option.map(Printf.sprintf"[%s]")separatorinletchildren_str=String.concat" "(List.mappp_builtin_syntaxchildren)inPrintf.sprintf"(%s)%s%s"children_str(Option.default""sep)quant(* Folds over a list by gathering a list while keeping track of an accumulator *)letfold_gatherfaccitems=let(final_acc,mapped)=List.fold_left(funaccitem->let(next_acc,mapped)=f(fstacc)itemin(next_acc,mapped::sndacc))(acc,[])itemsin(final_acc,List.revmapped)(* Snippet syntax following https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#snippet_syntax *)letrecbuiltin_syntax_to_snippet(tabstop:int)(syntax:builtin_syntax):int*string=matchsyntaxwith|Literal{value;subscript}->(tabstop,matchsubscriptwith|Somesub->Printf.sprintf"%s_%s"valuesub|None->value)|Reference{value;subscript}->letdefault=(matchsubscriptwith|Somesub->Printf.sprintf"%s_${%s}"valuesub|None->value)in(tabstop+1,Printf.sprintf"${%d:%s}"tabstopdefault)|Alternative{children}->(* snippet syntax for alternatives is not recursive, so we just show the pretty print of the syntax *)(tabstop+1,Printf.sprintf"${%d|%s|}"tabstop(String.concat","(List.mappp_builtin_syntaxchildren)))|Repeat{min;max=_;separator;children}->(* build `min` times carrying on the tabstop *)let(next_tabstop,child_snippets)=fold_gather(funtabstop_->let(next_tabstop,snippets)=fold_gatherbuiltin_syntax_to_snippettabstopchildrenin(next_tabstop,String.concat" "snippets))tabstop(List.initminFun.id)inletrepeat_snippet=String.concat(Option.default""separator)child_snippetsin(next_tabstop,repeat_snippet)letbuiltin_syntax_list_to_snippet(syntax_list:builtin_syntaxlist):string=lettop=snd(fold_gatherbuiltin_syntax_to_snippet1syntax_list)in(* we assume all grammars have an implicit "." at the end *)String.concat" "(List.filter(funs->s<>"")top)^"."(* This is what is stored in the JSON index *)typebuiltin_item_raw={(* documentation file where this builtin is documented *)documentation_path:string;(* page anchor for this builtin in the documentation *)documentation_anchor:string;(* grammar *)syntax:builtin_syntaxlist;(* simplified documentation *)documentation:string;}[@@derivingof_yojson]typebuiltin_item_kind=|Command(* We extend the raw item with additional computed fields *)typebuiltin_item={raw:builtin_item_raw;(* human-friendly label *)label:string;kind:builtin_item_kind;(* snippet syntax *)snippet:string;(* URL to the documentation page *)documentation_url:string;}(* The doc version should agree with what indices we have loaded *)[%%ifrocq="9.3"]letdoc_version="V9.3"[%%else](* TODO: Until 9.3 is not released in the refman, we point to 9.2 *)letdoc_version="V9.2.0"[%%endif]letdocumentation_url_of_item(item:builtin_item_raw):string=Printf.sprintf"https://rocq-prover.org/doc/%s/refman/%s.html#%s"doc_versionitem.documentation_pathitem.documentation_anchortypebuiltin_index=builtin_itemlistmoduleBuiltinIndices=structtypet={commands:builtin_index;}letload_builtin_index(kind:builtin_item_kind)(json_str:string):builtin_index=letjson=Yojson.Safe.from_stringjson_strinletpairs=Yojson.Safe.Util.to_assocjsoninList.map(fun(key,json_value)->letraw=builtin_item_raw_of_yojsonjson_valuein{raw;label=key;kind;snippet=builtin_syntax_list_to_snippetraw.syntax;documentation_url=documentation_url_of_itemraw;})pairs[%%ifrocq="9.3"]letv:t={commands=load_builtin_indexCommand[%blob"indices/9.3/cmdindex.json"];}[%%else](* For version for which we do not have JSON indices, we load the v9.3 indices. *)(* This will of course lead to situations where we suggest to the user something *)(* that is potentially non-existent or outdated, but this experience is better *)(* than giving the user nothing. *)letv:t={commands=load_builtin_indexCommand[%blob"indices/9.3/cmdindex.json"];}[%%endif]end(** Completion items *)(*
We define completion items which may either come from the library itself (for
example defined by the user or from an external library) or from the builtin
index prepared above.
*)typecompletion_level=Fully|Partially|No_completionletsymbol_prefix(completes:completion_leveloption)=matchcompleteswith|None->""|Somelevel->matchlevelwith|Fully->"★ "|Partially->"☆ "|No_completion->""typecompletion_item_lib={ref:Names.GlobRef.t;path:full_path;typ:types;env:Environ.env;sigma:Evd.evar_map;completes:completion_leveloption;mutabledebug_info:string;}typecompletion_item=|Libraryofcompletion_item_lib|Builtinofbuiltin_itemletmk_completion_item_libsigmarefenv(c:constr):completion_item_lib={ref;path=path_of_globalref;typ=c;env;sigma;completes=None;debug_info="";}letpp_completion_item_lib(item:completion_item_lib):(string*string*string*string*string)=letpr=pr_globalitem.refinletname=Pp.string_of_ppcmdsprinletpath=string_of_pathitem.pathinlettyp=Pp.string_of_ppcmds(pr_ltype_envitem.envitem.sigmaitem.typ)in(Printf.sprintf"%s%s"(symbol_prefixitem.completes)name,name,typ,path,item.debug_info)