Skip to content

Commit

Permalink
[lsp] Implement event loop processing Thread
Browse files Browse the repository at this point in the history
This is the result of today hacking, just an experiment, but includes
an optimization that is useful to avoid repeated checking.
  • Loading branch information
ejgallego committed Jul 6, 2022
1 parent 17818db commit 261d964
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 22 deletions.
12 changes: 8 additions & 4 deletions controller/coq_doc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,14 @@ let process_and_parse ~ofmt ~uri ~version ~coq_queue doc =
(* We interpret the command now *)
| Process ast -> (
let loc = Coq_ast.loc ast in
if Lsp.Debug.parsing then
(let line = Option.cata (fun loc -> "[l: " ^ string_of_int loc.Loc.line_nb ^ "] ") "" loc in
Lsp.Io.log_error "coq"
("parsed sentence: " ^ line ^ Pp.string_of_ppcmds (Coq_ast.print ast)));
(if Lsp.Debug.parsing then
let line =
Option.cata
(fun loc -> "[l: " ^ string_of_int loc.Loc.line_nb ^ "] ")
"" loc
in
Lsp.Io.log_error "coq"
("parsed sentence: " ^ line ^ Pp.string_of_ppcmds (Coq_ast.print ast)));
register_hack_proof_recover ast st;
(* memory is disabled as it is quite slow and misleading *)
let { Memo.Stats.res; cache_hit; memory = _; time } =
Expand Down
61 changes: 47 additions & 14 deletions controller/coq_lsp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,20 @@ let memo_read_from_disk () =
()

let memo_read_from_disk () = if false then memo_read_from_disk ()
let event_queue = ref (Queue.create ())

let queue_optimize dict =
(* remove redudant didChanges *)
let new_method = string_field "method" dict in
if String.equal new_method "textDocument/didChange" then
match Queue.peek_opt !event_queue with
| None -> ()
| Some dict' ->
let top_method = string_field "method" dict' in
if String.equal top_method "textDocument/didChange" then (
LIO.log_error "queue"
"dropped redundant didChange from top of the queue";
ignore (Queue.pop !event_queue))

exception Lsp_exit

Expand All @@ -252,6 +266,7 @@ exception Lsp_exit
future. *)
let dispatch_message ofmt ~state dict =
let id = oint_field "id" dict in
(* LIO.log_error "lsp" ("recv request id: " ^ string_of_int id); *)
let params = odict_field "params" dict in
match string_field "method" dict with
(* Requests *)
Expand All @@ -271,16 +286,32 @@ let dispatch_message ofmt ~state dict =
| "initialized" | "workspace/didChangeWatchedFiles" -> ()
| msg -> LIO.log_error "no_handler" msg

let process_input ofmt ~state (com : J.t) =
try dispatch_message ofmt ~state (U.to_assoc com) with
| U.Type_error (msg, obj) -> LIO.log_object msg obj
| Lsp_exit -> raise Lsp_exit
| exn ->
let bt = Printexc.get_backtrace () in
LIO.log_error "process_input" (Printexc.to_string exn);
LIO.log_error "process_input"
Pp.(string_of_ppcmds CErrors.(iprint (Exninfo.capture exn)));
LIO.log_error "BT" bt
let process_input (com : J.t) =
let dict = U.to_assoc com in
(* Optimization: don't stack multiple didChange msgs *)
queue_optimize dict;
Queue.add dict !event_queue;
()

let rec process_queue ofmt ~state =
(match Queue.peek_opt !event_queue with
| None ->
(* LIO.log_error "process_queue" "queue is empty, yielding!"; *)
Thread.delay 0.1
| Some com -> (
(* TODO we should optimize the queue *)
ignore (Queue.pop !event_queue);
LIO.log_error "process_queue" "We got job to do";
try dispatch_message ofmt ~state com with
| U.Type_error (msg, obj) -> LIO.log_object msg obj
| Lsp_exit -> raise Lsp_exit
| exn ->
let bt = Printexc.get_backtrace () in
LIO.log_error "process_input" (Printexc.to_string exn);
LIO.log_error "process_input"
Pp.(string_of_ppcmds CErrors.(iprint (Exninfo.capture exn)));
LIO.log_error "BT" bt));
process_queue ofmt ~state

let lsp_main log_file std vo_load_path ml_include_path =
LSP.std_protocol := std;
Expand Down Expand Up @@ -318,16 +349,18 @@ let lsp_main log_file std vo_load_path ml_include_path =

memo_read_from_disk ();

let rec loop state =
let (_ : Thread.t) = Thread.create (fun () -> process_queue oc ~state) () in

let rec loop () =
(* XXX: Implement a queue, compact *)
let com = LIO.read_request stdin in
if Lsp.Debug.read then LIO.log_object "read" com;
process_input oc ~state com;
process_input com;
F.pp_print_flush lp_fmt ();
flush lp_oc;
loop state
loop ()
in
try loop state with
try loop () with
| (LIO.ReadError "EOF" | Lsp_exit) as exn ->
LIO.log_error "main"
("exiting" ^ if exn = Lsp_exit then "" else " [uncontrolled LSP shutdown]");
Expand Down
2 changes: 1 addition & 1 deletion controller/dune
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
; Unfortunate we have to link the STM due to the LTAC plugin
; depending on it, we should fix this upstream
(libraries coq-core.vernac coq-core.stm coq-serapi.serlib
coq-serapi.sertop_v8_12 lsp cmdliner))
coq-serapi.sertop_v8_12 threads lsp cmdliner))
2 changes: 1 addition & 1 deletion lsp/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(library
(name lsp)
(libraries yojson))
(libraries yojson threads))
11 changes: 9 additions & 2 deletions lsp/io.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@
module F = Format
module J = Yojson.Basic

let mut = Mutex.create ()
let debug_fmt = ref F.err_formatter
let log_error hdr msg = F.fprintf !debug_fmt "[%s]: @[%s@]@\n%!" hdr msg

let log_error hdr msg =
Mutex.lock mut;
F.fprintf !debug_fmt "[%s]: @[%s@]@\n%!" hdr msg;
Mutex.unlock mut

let log_object hdr obj =
F.fprintf !debug_fmt "[%s]: @[%a@]@\n%!" hdr J.(pretty_print ~std:false) obj
Expand Down Expand Up @@ -55,7 +60,9 @@ let read_request ic =
| Invalid_argument msg -> raise (ReadError msg)

let send_json fmt obj =
Mutex.lock mut;
if Debug.send then log_object "send" obj;
let msg = F.asprintf "%a" J.(pretty_print ~std:true) obj in
let size = String.length msg in
F.fprintf fmt "Content-Length: %d\r\n\r\n%s%!" size msg
F.fprintf fmt "Content-Length: %d\r\n\r\n%s%!" size msg;
Mutex.unlock mut

0 comments on commit 261d964

Please sign in to comment.