diff --git a/lib/language_server/Diagnostics.ml b/lib/language_server/Diagnostics.ml index d358d5c..12e0e89 100644 --- a/lib/language_server/Diagnostics.ml +++ b/lib/language_server/Diagnostics.ml @@ -27,53 +27,51 @@ let publish_for (forest : State.t) (lsp_uri : Lsp.Uri.t) let published : (string, unit) Hashtbl.t = Hashtbl.create 64 let compute (document : Lsp.Text_document.t) = - let Lsp_state.{forest; ready; _} = Lsp_state.get () in - if !ready then begin - let lsp_uri = Lsp.Text_document.documentUri document in - let uri = URI.of_lsp_uri ~base:forest.config.url lsp_uri in - ignore (Link_checker.recheck ~forest uri); - (* Diagnostics are stored per URI, but we need to publish per file *) - let targets = ref (URI.Set.singleton uri) in - let record u = - targets := URI.Set.add (State.parent_file_uri ~forest u) !targets + let Lsp_state.{forest; ready = is_ready, _; _} = Lsp_state.get () in + Eio.Promise.await is_ready; + let lsp_uri = Lsp.Text_document.documentUri document in + let uri = URI.of_lsp_uri ~base:forest.config.url lsp_uri in + ignore (Link_checker.recheck ~forest uri); + (* Diagnostics are stored per URI, but we need to publish per file *) + let targets = ref (URI.Set.singleton uri) in + let record u = + targets := URI.Set.add (State.parent_file_uri ~forest u) !targets + in + State.iter_diagnostics (fun u _ -> record u) forest; + let dirty_owners = + State.with_lock forest (fun () -> + Duplicates.reset_dirty_owners forest.duplicates) + in + URI.Set.iter record dirty_owners; + let by_path : (string, Lsp.Uri.t * Error.t list) Hashtbl.t = + Hashtbl.create 16 + in + begin + (* For each publishing target *) + let@ root = URI.Set.iter @~ !targets in + let@ doc = Option.iter @~ State.get_document ~forest root in + let root_lsp_uri = Lsp.Text_document.documentUri doc in + (* Gather regular and duplicate-tree diagnostics *) + let owned = + List.concat_map + (State.get_diagnostics ~forest) + (Duplicates.owned_subtrees forest.duplicates root) in - State.iter_diagnostics (fun u _ -> record u) forest; - let dirty_owners = - State.with_lock forest (fun () -> - Duplicates.reset_dirty_owners forest.duplicates) - in - URI.Set.iter record dirty_owners; - let by_path : (string, Lsp.Uri.t * Error.t list) Hashtbl.t = - Hashtbl.create 16 - in - begin - (* For each publishing target *) - let@ root = URI.Set.iter @~ !targets in - let@ doc = Option.iter @~ State.get_document ~forest root in - let root_lsp_uri = Lsp.Text_document.documentUri doc in - (* Gather regular and duplicate-tree diagnostics *) - let owned = - List.concat_map - (State.get_diagnostics ~forest) - (Duplicates.owned_subtrees forest.duplicates root) - in - Hashtbl.replace by_path - (Lsp.Uri.to_path root_lsp_uri) - (root_lsp_uri, State.get_diagnostics ~forest root @ owned) - end; - (* For previously published diagnostics *) - published - |> Hashtbl.iter (fun path () -> - (* If they no longer have diagnostics, clear the entry *) - if not (Hashtbl.mem by_path path) then - Hashtbl.replace by_path path (Lsp.Uri.of_path path, [])); - by_path - |> Hashtbl.iter (fun path (target, diagnostics) -> - begin match diagnostics with - (* and publish the empty list to clear the editors diagnostics*) - | [] -> Hashtbl.remove published path - | _ -> Hashtbl.replace published path () - end; - publish_for forest target diagnostics) - end - else () + Hashtbl.replace by_path + (Lsp.Uri.to_path root_lsp_uri) + (root_lsp_uri, State.get_diagnostics ~forest root @ owned) + end; + (* For previously published diagnostics *) + published + |> Hashtbl.iter (fun path () -> + (* If they no longer have diagnostics, clear the entry *) + if not (Hashtbl.mem by_path path) then + Hashtbl.replace by_path path (Lsp.Uri.of_path path, [])); + by_path + |> Hashtbl.iter (fun path (target, diagnostics) -> + begin match diagnostics with + (* and publish the empty list to clear the editors diagnostics*) + | [] -> Hashtbl.remove published path + | _ -> Hashtbl.replace published path () + end; + publish_for forest target diagnostics) diff --git a/lib/language_server/Forester_lsp.ml b/lib/language_server/Forester_lsp.ml index b89c9ef..b08fba1 100644 --- a/lib/language_server/Forester_lsp.ml +++ b/lib/language_server/Forester_lsp.ml @@ -205,7 +205,7 @@ let start ~env ~sw ~port ~serve ~(config_path : string option) = let config = Forester_frontend.Forester.with_docs_foreign config in let forest = State.make ~sw ~env ~config ~dev:true in let addr_completions = URI.Tbl.create 1000 in - let ready = ref false in + let (is_ready, set_ready) as ready = Eio.Promise.create () in Eio.Switch.run @@ fun fiber_sw -> if serve then begin let@ () = Eio.Fiber.fork_daemon ~sw:fiber_sw in @@ -222,7 +222,7 @@ let start ~env ~sw ~port ~serve ~(config_path : string option) = end; let@ () = Server.run - ~init:{forest; lsp_io; should_shutdown = false; addr_completions; ready} + ~init:{forest; lsp_io; should_shutdown = false; addr_completions; ready } in begin initialize (); @@ -232,6 +232,6 @@ let start ~env ~sw ~port ~serve ~(config_path : string option) = ignore (Link_checker.check_all ~forest); let fresh_completions = Completion.populate_addr_completions ~forest in URI.Tbl.iter (URI.Tbl.replace addr_completions) fresh_completions; - ready := true + Eio.Promise.resolve set_ready () end; event_loop () diff --git a/lib/language_server/Lsp_state.ml b/lib/language_server/Lsp_state.ml index d6ae951..2ecda5d 100644 --- a/lib/language_server/Lsp_state.ml +++ b/lib/language_server/Lsp_state.ml @@ -13,7 +13,7 @@ type state = { should_shutdown: bool; lsp_io: LspEio.io; addr_completions: Lsp.Types.CompletionItem.t URI.Tbl.t; - ready: bool ref; + ready: unit Eio.Promise.t * unit Eio.Promise.u; } module M = Algaeff.State.Make (struct