1010(* Status: Very Experimental *)
1111(* ***********************************************************************)
1212
13- open Lplib open Extra
13+ open Lplib
1414open Common
1515open Core
1616
@@ -59,17 +59,8 @@ let do_check_text ofmt ~doc =
5959 try
6060 Lp_doc. check_text ~doc
6161 with Common.Error. Fatal (_pos , msg , err_desc ) ->
62- let loc : Pos.pos =
63- {
64- fname = Some (doc.uri);
65- start_line = 0 ;
66- start_col = 0 ;
67- start_offset = 0 ;
68- end_line = 0 ;
69- end_col = 0 ;
70- end_offset = 0 ;
71- } in
72- (doc, Lp_doc. mk_error ~doc loc (msg ^ " \n " ^ err_desc))
62+ (doc, Lp_doc. mk_error ~doc (Pos. file_start doc.uri)
63+ (msg ^ " \n " ^ err_desc))
7364 in
7465 Hashtbl. replace doc_table doc.uri doc;
7566 Hashtbl. replace completed_table doc.uri doc;
@@ -131,9 +122,11 @@ let mk_syminfo file (name, _path, kind, pos) : J.t =
131122 ]
132123 ]
133124
125+ (* [file] is a plain filesystem path (as produced by
126+ [Library.file_of_path]), never a URI. *)
134127let mk_definfo file pos =
135128 `Assoc [
136- " uri" , `String file
129+ " uri" , `String ( " file:// " ^ file)
137130 ; " range" , LSP. mk_range pos
138131 ]
139132
@@ -157,6 +150,7 @@ let do_symbols ofmt ~id params =
157150 let msg = LSP. mk_reply ~id ~result: `Null in
158151 LIO. send_json ofmt msg
159152 | Some ss ->
153+ Pure. restore_time ss;
160154 let sym = Pure. get_symbols ss in
161155 let sym =
162156 Extra.StrMap. fold
@@ -231,9 +225,10 @@ let get_node_at_pos doc line pos =
231225 List. find_opt (fun { ast; _ } ->
232226 let loc = Pure.Command. get_pos ast in
233227 let res = in_range ?loc (line,pos) in
234- let ls = Format. asprintf " %B l:%d p:%d / %a"
235- res line pos Pos. pp loc in
236- LIO. log_error " get_node_at_pos" (" call: " ^ ls);
228+ (* trace, per command node, whether the query (line,pos) falls in its
229+ range [loc] (header "get_node_at_pos") *)
230+ LIO. log_error " get_node_at_pos"
231+ (Format. asprintf " %b l:%d p:%d / %a" res line pos Pos. pp loc);
237232 res
238233 ) doc.Lp_doc. nodes
239234
@@ -272,24 +267,18 @@ let rec get_goals ~doc ~line ~pos =
272267 | Some (v ,_ ) -> Some v
273268
274269let get_logs ~doc ~line ~pos : string =
275- (* DEBUG LOG START *)
270+ (* Log the query location and one line per document log element: its
271+ severity, source position and a 30-char message preview (header
272+ "get_logs"). *)
273+ let elt ((sev , msg ), po ) =
274+ let loc = match po with
275+ | Some p -> Printf. sprintf " %d,%d" p.Pos. start_line p.Pos. start_col
276+ | None -> " ?" in
277+ let preview = String. sub msg 0 (min 30 (String. length msg)) in
278+ Format. asprintf " sev:%d @%s %S" sev loc preview in
276279 LIO. log_error " get_logs"
277- (Printf. sprintf " %s:%d,%d" doc.Lp_doc. uri line pos);
278- let log_to_str ((sev , log ), posopt ) =
279- let pos_str =
280- match posopt with
281- | None -> " None"
282- | Some Pos. {start_line; start_col; _} ->
283- Printf. sprintf " (%d, %d)" start_line start_col
284- in
285- let log_str =
286- let len = String. length log in
287- Printf. sprintf " length: %d | %s" len (String. sub log 0 (min 30 len))in
288- Format. asprintf " element(severity:%d): %s -> %s\n " sev pos_str log_str
289- in
290- Lsp_io. log_error " get_logs"
291- (List. fold_left (^ ) " \n " (List. map log_to_str doc.Lp_doc. logs));
292- (* DEBUG LOG END *)
280+ (Printf. sprintf " %s:%d,%d\n %s" doc.Lp_doc. uri line pos
281+ (String. concat " \n " (List. map elt doc.Lp_doc. logs)));
293282 let line = line+ 1 in
294283 let end_limit =
295284 match get_first_error doc with
@@ -318,20 +307,30 @@ let do_goals ofmt ~id params =
318307 let msg = LSP. mk_reply ~id ~result in
319308 LIO. send_json ofmt msg
320309
321- let msg_fail hdr msg =
322- LIO. log_error hdr msg;
323- failwith msg
324310
325- let get_symbol : Range. point ->
326- ('a * 'b ) RangeMap. t -> ('b * Range. t ) option
311+ let get_symbol : Range. point -> 'a RangeMap. t -> ('a * Range. t ) option
327312= fun pos doc ->
328313
329314 let open RangeMap in
330315
331316 match (find pos doc) with
332317 | None -> None
333- | Some (interval , (_ , token )) -> Some (token, interval)
334-
318+ | Some (interval , value ) -> Some (value, interval)
319+
320+ (* Dump, to the LSP debug log, the two tables consulted when resolving the
321+ symbol under the cursor: the token map ("token map": each source range ->
322+ identifier), and the in-scope symbols with their declaration positions
323+ ("symbol map"). Diagnostic aid for failed go-to-definition / hover. *)
324+ let log_symbol_maps doc ss =
325+ LIO. log_error " token map" (RangeMap. to_string snd doc.Lp_doc. map);
326+ let syms =
327+ Pure. get_symbols ss
328+ |> Extra.StrMap. bindings
329+ |> List. map (fun (name , s ) ->
330+ Format. asprintf " %s: @[%a@]" name Pos. pp s.Term. sym_pos)
331+ |> String. concat " \n "
332+ in
333+ LIO. log_error " symbol map" syms
335334
336335let do_definition ofmt ~id params =
337336
@@ -341,122 +340,65 @@ let do_definition ofmt ~id params =
341340 let msg = LSP. mk_reply ~id ~result: `Null in
342341 LIO. send_json ofmt msg
343342 | Some ss ->
343+ Pure. restore_time ss;
344+ log_symbol_maps doc ss;
344345 let ln, pos = get_textPosition params in
345346
346- (* Lines send by the client start at 0 *)
347+ (* Lines sent by the client start at 0 *)
347348 let pt = Range. make_point (ln + 1 ) pos in
348- let sym_target =
349- match get_symbol pt doc.map with
350- | None -> " No symbol found"
351- | Some (token , _ ) -> token
352- in
353-
354- (* Some printing in the log*)
355- LIO. log_error " token map" (RangeMap. to_string snd doc.map);
356- LIO. log_error " do_definition" sym_target;
357-
358- let sym = Pure. get_symbols ss in
359- let map_pp : string =
360- Extra.StrMap. bindings sym
361- |> List. map (fun (key , sym ) ->
362- Format. asprintf " {%s} / %s: @[%a@]"
363- key sym.Term. sym_name Pos. pp sym.sym_pos)
364- |> String. concat " \n "
365- in
366- LIO. log_error " symbol map" map_pp;
367-
368349 let sym_info =
369- match StrMap. find_opt sym_target sym with
370- | None -> `Null
371- | Some s ->
372- match s.sym_pos with
350+ match get_symbol pt doc.map with
351+ | None ->
352+ LIO. log_error " do_definition" " no symbol at point" ; `Null
353+ | Some (qid , _ ) ->
354+ LIO. log_error " do_definition" (snd qid);
355+ match Pure. find_sym ss qid with
373356 | None -> `Null
374- | Some pos ->
375- (* A JSON with the path towards the definition of the term
376- and its position is returned
377- /!\ : extension is fixed, only works for .lp files *)
378- mk_definfo
379- Library. (file_of_path s.Term. sym_path ^ lp_src_extension) pos
357+ (* Ghost symbols (internal symbols used e.g. for unification
358+ rules and string literals) have no user-facing definition
359+ site one could jump to. *)
360+ | Some s when s.Term. sym_path = Sign.Ghost. path -> `Null
361+ | Some s ->
362+ let file =
363+ Library. (file_of_path s.Term. sym_path ^ lp_src_extension) in
364+ let pos = Option. get (Pos. file_start file) s.sym_pos in
365+ mk_definfo file pos
380366 in
381367 let msg = LSP. mk_reply ~id ~result: sym_info in
382368 LIO. send_json ofmt msg
383369
384370let hover_symInfo ofmt ~id params =
385-
386371 let _, _, doc = grab_doc params in
387372 let ln, pos = get_textPosition params in
388-
389- (* Positions sent by the client are one line late *)
390373 let pt = Range. make_point (ln + 1 ) pos in
391- LIO. log_error " searched point" (Range. point_to_string pt);
392-
393- (* The hovered token and its start/finish positions are stored *)
394- let sym_target, interval =
395- match get_symbol pt doc.map with
396- | None ->
397- " No symbol found" , (Range. make_interval pt pt)
398- (* VSCode highlights the token properly if the interval is extended to the
399- character next to it. This might be handled differently in other
400- editors in the future, but it is the most practical solution for
401- now. *)
402- | Some (token , range ) ->
403- token, (Range. translate range 0 1 )
404- in
374+ LIO. log_error " hover_symInfo" (Range. point_to_string pt);
405375
406- (* Some printing in the log *)
407- (* LIO.log_error "token map" (RangeMap.to_string snd doc.map);
408-
409- LIO.log_error "hoverSymInfo" sym_target;
410- LIO.log_error "hoverSymInfo" (Range.interval_to_string interval); *)
376+ let send_null () =
377+ LIO. send_json ofmt (LSP. mk_reply ~id ~result: `Null )
378+ in
411379
412380 try
413- (* The information about the tokens is stored *)
414- let sym =
415- match doc.final with
416- | Some ss -> Pure. get_symbols ss
417- | None -> raise (Error. fatal_no_pos(" Root state is missing
418- probably because new_doc has raised exception" )) in
419-
420- (* The start/finish positions are used to hover the full qualified term,
421- not just the token *)
422- let start = Range. interval_start interval
423- and finish = Range. interval_end interval in
424-
425- (* FIXME: types and typed conversion should take care of this *)
426- let sl, sc, fl, fc =
427- (Range. line start - 1 ),
428- (Range. column start - 1 ),
429- (Range. line finish - 1 ),
430- (Range. column finish - 1 )
431- in
432-
433- let s = `Assoc [" line" , `Int sl; " character" , `Int sc] in
434- let f = `Assoc [" line" , `Int fl; " character" , `Int fc] in
435- let range = `Assoc [" start" , s; " end" , f] in
436-
437- let map_pp : string =
438- Extra.StrMap. bindings sym
439- |> List. map (fun (key , sym ) ->
440- Format. asprintf " {%s} / %s: @[%a@]"
441- key sym.Term. sym_name Pos. pp sym.sym_pos)
442- |> String. concat " \n "
443- in
444- LIO. log_error " symbol map" map_pp;
445-
446- let sym_found =
447- match StrMap. find_opt sym_target sym with
448- | None -> msg_fail " hover_SymInfo" " Sym not found"
449- | Some sym -> sym
450- in
451- let sym_type = Format. asprintf " %a" Core.Print. sym_type sym_found in
452- let result : J.t =
453- `Assoc [ " contents" , `String sym_type; " range" , range ] in
454- let msg = LSP. mk_reply ~id ~result in
455- LIO. send_json ofmt msg
456-
457- with _ ->
458- let msg = LSP. mk_reply ~id ~result: `Null in
459- LIO. send_json ofmt msg
381+ let ss = match doc.final with
382+ | Some ss -> ss
383+ | None ->
384+ raise (Error. fatal_no_pos " Final state is missing: the document \
385+ was never successfully loaded" ) in
386+ Pure. restore_time ss;
387+ log_symbol_maps doc ss;
388+
389+ match get_symbol pt doc.map with
390+ | None -> send_null ()
391+ | Some (qid , range ) ->
392+ match Pure. find_sym ss qid with
393+ | None -> LIO. log_error " hover_symInfo" " Sym not found" ; send_null ()
394+ | Some sym_found ->
395+ let sym_type = Format. asprintf " %a" Core.Print. sym_type sym_found in
396+ let result = `Assoc [ " contents" , `String sym_type
397+ ; " range" , LSP. mk_range_of_interval range ] in
398+ LIO. send_json ofmt (LSP. mk_reply ~id ~result )
399+ with e ->
400+ LIO. log_error " hover_symInfo" (Printexc. to_string e);
401+ send_null ()
460402
461403let protect_dispatch p f x =
462404 try f x
@@ -488,10 +430,12 @@ let dispatch_message ofmt dict =
488430 (do_symbols ofmt ~id ) params
489431
490432 | "textDocument/hover" ->
491- hover_symInfo ofmt ~id params
433+ (try hover_symInfo ofmt ~id params
434+ with _ -> LIO. send_json ofmt (LSP. mk_reply ~id ~result: `Null ))
492435
493436 | "textDocument/definition" ->
494- do_definition ofmt ~id params
437+ (try do_definition ofmt ~id params
438+ with _ -> LIO. send_json ofmt (LSP. mk_reply ~id ~result: `Null ))
495439
496440 | "proof/goals" ->
497441 do_goals ofmt ~id params
@@ -528,13 +472,12 @@ let process_input ofmt (com : J.t) =
528472 let bt = Printexc. get_backtrace () in
529473 LIO. log_error " [BT]" bt;
530474 LIO. log_error " process_input" (Printexc. to_string exn );
531- (* Send an "empty" answer with Null goals when exception occurs*)
532- let id = oint_field " id" (U. to_assoc com) in
533- let goals = None in
534- let logs = " " in
535- let result = LSP. json_of_goals goals ~logs in
536- let msg = LSP. mk_reply ~id ~result in
537- LIO. send_json ofmt msg
475+ (* Send a null reply so the client doesn't hang *)
476+ let id = oint_field " id" (U. to_assoc com) in
477+ if id <> 0 then begin
478+ let msg = LSP. mk_reply ~id ~result: `Null in
479+ LIO. send_json ofmt msg
480+ end
538481
539482let main std log_file =
540483
0 commit comments