···11-open Brr
22-module Worker = Brr_webworkers.Worker
11+module type WORKER = sig
22+ type t
33+ val post : t -> Protocol.action -> unit
44+end
3544-(* When a query is sent to the Worker we keep the Future result in an indexed
55-table so that the on_message function will be able to determine the Future when
66-the answer is posted by the Worker.
77-The Worker works synchronously so we expect answer to arrive in order. *)
88-type worker = {
99- worker: Worker.t;
1010- queue: (Protocol.answer -> unit) Queue.t
1111-}
66+module Make (Worker : WORKER) = struct
77+ (* When a query is sent to the Worker we keep the Future result in an indexed
88+ table so that the on_message function will be able to determine the Future when
99+ the answer is posted by the Worker.
1010+ The Worker works synchronously so we expect answer to arrive in order. *)
1111+ type worker = {
1212+ worker: Worker.t;
1313+ queue: (Protocol.answer -> unit) Queue.t
1414+ }
12151313-let add_fut worker res = Queue.add res worker.queue
1414-let res_fut worker v = (Queue.take worker.queue) v
1616+ let add_fut worker res = Queue.add res worker.queue
1717+ let res_fut worker v = (Queue.take worker.queue) v
15181616-let make_worker url =
1717- let worker = Worker.create @@ Jstr.of_string url in
1818- let queue = Queue.create () in
1919- let worker = { worker; queue } in
2020- let on_message m =
2121- let m = Ev.as_type m in
2222- let data_marshaled : bytes = Brr_io.Message.Ev.data m in
2323- let data : Protocol.answer = Marshal.from_bytes data_marshaled 0 in
2424- res_fut worker data
2525- in
2626- let _listener =
2727- Ev.listen Brr_io.Message.Ev.message on_message @@
2828- Worker.as_target worker.worker
2929- in
3030- worker
1919+ let on_message worker data = res_fut worker data
31203232-(* todo share that with worker *)
3333-type action = Completion | Type_enclosing | Errors
2121+ let make_worker worker =
2222+ let queue = Queue.create () in
2323+ { worker; queue }
34243535-type errors = Protocol.error list
2525+ (* todo share that with worker *)
2626+ type action = Completion | Type_enclosing | Errors
36273737-let query ~action worker (*todo: other queries*) =
3838- let fut, set = Fut.create () in
3939- add_fut worker set;
4040- Worker.post worker.worker (Marshal.to_bytes action []);
4141- fut
2828+ type errors = Protocol.error list
42294343-let query_errors worker (source : string) =
4444- let open Fut.Syntax in
4545- let action = Protocol.All_errors source in
4646- let+ data : Protocol.answer = query ~action worker in
4747- Console.(log ["Received errors:"; data]);
4848- match data with
4949- | Protocol.Errors errors -> errors
5050- | _ -> assert false
3030+ let query ~action worker (*todo: other queries*) =
3131+ let fut, set = Fut.create () in
3232+ add_fut worker set;
3333+ Worker.post worker.worker action;
3434+ fut
51355252-let query_completions worker (source : string) position =
5353- let open Fut.Syntax in
5454- let action = Protocol.Complete_prefix (source, position) in
5555- let+ data : Protocol.answer = query ~action worker in
5656- Console.(log ["Received completions:"; data]);
5757- match data with
5858- | Protocol.Completions compl -> compl
5959- | _ -> assert false
3636+ let query_errors worker (source : string) =
3737+ let open Fut.Syntax in
3838+ let action = Protocol.All_errors source in
3939+ let+ data : Protocol.answer = query ~action worker in
4040+ match data with
4141+ | Protocol.Errors errors -> errors
4242+ | _ -> assert false
60436161-let query_type worker (source : string) position =
6262- let open Fut.Syntax in
6363- let action = Protocol.Type_enclosing (source, position) in
6464- let+ data : Protocol.answer = query ~action worker in
6565- Console.(log ["Received typed enclosings:"; data]);
6666- match data with
6767- | Protocol.Typed_enclosings l -> l
6868- | _ -> assert false
4444+ let query_completions worker (source : string) position =
4545+ let open Fut.Syntax in
4646+ let action = Protocol.Complete_prefix (source, position) in
4747+ let+ data : Protocol.answer = query ~action worker in
4848+ match data with
4949+ | Protocol.Completions compl -> compl
5050+ | _ -> assert false
69517070-let add_cmis worker cmis =
7171- let open Fut.Syntax in
7272- let action = Protocol.Add_cmis cmis in
7373- let+ data : Protocol.answer = query ~action worker in
7474- Console.(log ["Received response from adding cmis:"; data]);
7575- match data with
7676- | Protocol.Added_cmis -> ()
7777- | _ -> assert false5252+ let query_type worker (source : string) position =
5353+ let open Fut.Syntax in
5454+ let action = Protocol.Type_enclosing (source, position) in
5555+ let+ data : Protocol.answer = query ~action worker in
5656+ match data with
5757+ | Protocol.Typed_enclosings l -> l
5858+ | _ -> assert false
5959+6060+ let add_cmis worker cmis =
6161+ let open Fut.Syntax in
6262+ let action = Protocol.Add_cmis cmis in
6363+ let+ data : Protocol.answer = query ~action worker in
6464+ match data with
6565+ | Protocol.Added_cmis -> ()
6666+ | _ -> assert false
6767+end
6868+6969+module Webworker = struct
7070+ include Brr_webworkers.Worker
7171+7272+ let post t action =
7373+ let bytes = Marshal.to_bytes action [] in
7474+ post t bytes
7575+end
7676+7777+include Make (Webworker)
7878+7979+let make_worker url =
8080+ let worker = make_worker @@ Webworker.create @@ Jstr.of_string url in
8181+ let on_message m =
8282+ let m = Brr.Ev.as_type m in
8383+ let data_marshaled : bytes = Brr_io.Message.Ev.data m in
8484+ let data : Protocol.answer = Marshal.from_bytes data_marshaled 0 in
8585+ on_message worker data
8686+ in
8787+ let _listen =
8888+ Brr.Ev.listen Brr_io.Message.Ev.message on_message
8989+ @@ Webworker.as_target worker.worker
9090+ in
9191+ worker
+86-75
src/extension/merlin_codemirror.ml
···3344module Utils = Utils
5566-let linter worker = fun view ->
77- let open Fut.Syntax in
88- let doc = Utils.get_full_doc @@ Editor.View.state view in
99- let+ result = Merlin_client.query_errors worker doc in
1010- List.map (fun Protocol.{ kind; loc; main; sub = _; source } ->
1111- let from = loc.loc_start.pos_cnum in
1212- let to_ = loc.loc_end.pos_cnum in
1313- let source = Protocol.report_source_to_string source in
1414- let severity = match kind with
1515- | Report_error
1616- | Report_warning_as_error _
1717- | Report_alert_as_error _ -> Lint.Diagnostic.Error
1818- | Report_warning _ -> Lint.Diagnostic.Warning
1919- | Report_alert _ -> Lint.Diagnostic.Info
2020- in
2121- Lint.Diagnostic.create ~source ~from ~to_ ~severity ~message:main ()
2222- ) result
2323- |> Array.of_list
66+let ocaml = Jv.get Jv.global "__CM__mllike" |> Stream.Language.of_jv
77+let ocaml = Stream.Language.define ocaml
2482525-let keywords = List.map
2626- (fun label ->
2727- Autocomplete.Completion.create ~label ~type_:"keyword" ())
2828- [
2929- "as"; "do"; "else"; "end"; "exception"; "fun"; "functor"; "if"; "in";
3030- "include"; "let"; "of"; "open"; "rec"; "struct"; "then"; "type"; "val";
3131- "while"; "with"; "and"; "assert"; "begin"; "class"; "constraint";
3232- "done"; "downto"; "external"; "function"; "initializer"; "lazy";
3333- "match"; "method"; "module"; "mutable"; "new"; "nonrec"; "object";
3434- "private"; "sig"; "to"; "try"; "value"; "virtual"; "when";
3535- ]
99+module Extensions (Worker : Merlin_client.WORKER) = struct
36103737-let merlin_completion worker = fun ctx ->
3838- let open Fut.Syntax in
3939- let source = Utils.get_full_doc @@ Autocomplete.Context.state ctx in
4040- let pos = Autocomplete.Context.pos ctx in
4141- let+ { from; to_; entries } =
4242- Merlin_client.query_completions worker source (`Offset pos)
4343- in
4444- let options =
4545- let num_completions = List.length entries in
4646- List.mapi (fun i Query_protocol.Compl.{ name; desc; _ } ->
4747- let boost = num_completions - i in
4848- Autocomplete.Completion.create ~label:name ~detail:desc ~boost ()) entries
4949- in
5050- Some (Autocomplete.Result.create ~filter:true ~from ~to_ ~options ())
1111+ module Merlin_client = Merlin_client.Make (Worker)
1212+ type worker = Merlin_client.worker
51135252-let autocomplete worker =
5353- let override = [
5454- Autocomplete.Source.from_list keywords;
5555- Autocomplete.Source.create @@ merlin_completion worker]
5656-in
5757- let config = Autocomplete.config () ~override in
5858- Autocomplete.create ~config ()
5959-6060-let tooltip_on_hover worker =
6161- let open Tooltip in
6262- hover_tooltip @@
6363- fun ~view ~pos ~side:_ ->
1414+ let linter worker = fun view ->
6415 let open Fut.Syntax in
6516 let doc = Utils.get_full_doc @@ Editor.View.state view in
6666- let pos = `Offset pos in
6767- let+ result = Merlin_client.query_type worker doc pos in
6868- match result with
6969- | (loc, `String type_, _)::_ ->
7070- let create _view =
7171- let dom = El.div [El.txt' type_] in
7272- Tooltip_view.create ~dom ()
1717+ let+ result = Merlin_client.query_errors worker doc in
1818+ List.map (fun Protocol.{ kind; loc; main; sub = _; source } ->
1919+ let from = loc.loc_start.pos_cnum in
2020+ let to_ = loc.loc_end.pos_cnum in
2121+ let source = Protocol.report_source_to_string source in
2222+ let severity = match kind with
2323+ | Report_error
2424+ | Report_warning_as_error _
2525+ | Report_alert_as_error _ -> Lint.Diagnostic.Error
2626+ | Report_warning _ -> Lint.Diagnostic.Warning
2727+ | Report_alert _ -> Lint.Diagnostic.Info
7328 in
7474- let pos = loc.loc_start.pos_cnum in
7575- let end_ = loc.loc_end.pos_cnum in
7676- Some (Tooltip.create ~pos ~end_ ~above:true ~arrow:true ~create ())
7777- | _ -> None
2929+ Lint.Diagnostic.create ~source ~from ~to_ ~severity ~message:main ()
3030+ ) result
3131+ |> Array.of_list
78327979-let ocaml = Jv.get Jv.global "__CM__mllike" |> Stream.Language.of_jv
8080-let ocaml = Stream.Language.define ocaml
3333+ let keywords = List.map
3434+ (fun label ->
3535+ Autocomplete.Completion.create ~label ~type_:"keyword" ())
3636+ [
3737+ "as"; "do"; "else"; "end"; "exception"; "fun"; "functor"; "if"; "in";
3838+ "include"; "let"; "of"; "open"; "rec"; "struct"; "then"; "type"; "val";
3939+ "while"; "with"; "and"; "assert"; "begin"; "class"; "constraint";
4040+ "done"; "downto"; "external"; "function"; "initializer"; "lazy";
4141+ "match"; "method"; "module"; "mutable"; "new"; "nonrec"; "object";
4242+ "private"; "sig"; "to"; "try"; "value"; "virtual"; "when";
4343+ ]
4444+4545+ let merlin_completion worker = fun ctx ->
4646+ let open Fut.Syntax in
4747+ let source = Utils.get_full_doc @@ Autocomplete.Context.state ctx in
4848+ let pos = Autocomplete.Context.pos ctx in
4949+ let+ { from; to_; entries } =
5050+ Merlin_client.query_completions worker source (`Offset pos)
5151+ in
5252+ let options =
5353+ let num_completions = List.length entries in
5454+ List.mapi (fun i Query_protocol.Compl.{ name; desc; _ } ->
5555+ let boost = num_completions - i in
5656+ Autocomplete.Completion.create ~label:name ~detail:desc ~boost ()) entries
5757+ in
5858+ Some (Autocomplete.Result.create ~filter:true ~from ~to_ ~options ())
5959+6060+ let autocomplete worker =
6161+ let override = [
6262+ Autocomplete.Source.from_list keywords;
6363+ Autocomplete.Source.create @@ merlin_completion worker]
6464+ in
6565+ let config = Autocomplete.config () ~override in
6666+ Autocomplete.create ~config ()
6767+6868+ let tooltip_on_hover worker =
6969+ let open Tooltip in
7070+ hover_tooltip @@
7171+ fun ~view ~pos ~side:_ ->
7272+ let open Fut.Syntax in
7373+ let doc = Utils.get_full_doc @@ Editor.View.state view in
7474+ let pos = `Offset pos in
7575+ let+ result = Merlin_client.query_type worker doc pos in
7676+ match result with
7777+ | (loc, `String type_, _)::_ ->
7878+ let create _view =
7979+ let dom = El.div [El.txt' type_] in
8080+ Tooltip_view.create ~dom ()
8181+ in
8282+ let pos = loc.loc_start.pos_cnum in
8383+ let end_ = loc.loc_end.pos_cnum in
8484+ Some (Tooltip.create ~pos ~end_ ~above:true ~arrow:true ~create ())
8585+ | _ -> None
8686+8787+ let linter worker = Lint.create (linter worker)
8888+8989+ let all_extensions worker = [|
9090+ linter worker;
9191+ autocomplete worker;
9292+ tooltip_on_hover worker
9393+ |]
9494+end
81958296module type Config = sig
8397 val worker_url : string
···90104 let _ = Merlin_client.add_cmis worker Config.cmis in
91105 worker
92106107107+ open Extensions (Merlin_client.Webworker)
108108+93109 let autocomplete = autocomplete worker
94110 let tooltip_on_hover = tooltip_on_hover worker
9595- let linter = Lint.create (linter worker)
9696-9797- let all_extensions = [|
9898- linter;
9999- autocomplete;
100100- tooltip_on_hover
101101- |]
111111+ let linter = linter worker
112112+ let all_extensions = all_extensions worker
102113end
+20
src/extension/merlin_codemirror.mli
···1818end
19192020module Make : functor (Config : Config) -> sig
2121+2122 val autocomplete : Code_mirror.Extension.t
2223 (** An extension providing completions when typing *)
2324···29303031 val all_extensions : Code_mirror.Extension.t array
3132 (** All the Merlin-specific extensions (does not include [ocaml]) *)
3333+3434+end
3535+3636+module Extensions (Worker : Merlin_client.WORKER) : sig
3737+3838+ type worker = Merlin_client.Make(Worker).worker
3939+4040+ val autocomplete : worker -> Code_mirror.Extension.t
4141+ (** An extension providing completions when typing *)
4242+4343+ val tooltip_on_hover : worker -> Code_mirror.Extension.t
4444+ (** An extension providing type-information when hovering code *)
4545+4646+ val linter : worker -> Code_mirror.Extension.t
4747+ (** An extension that highlights errors and warnings in the code *)
4848+4949+ val all_extensions : worker -> Code_mirror.Extension.t array
5050+ (** All the Merlin-specific extensions (does not include [ocaml]) *)
5151+3252end
+47-51
src/worker/worker.ml
···204204 Mconfig.dump (Mpipeline.final_config pipeline)
205205 |> Json.pretty_to_string *)
206206207207-let on_message marshaled_message =
208208- let action : Protocol.action =
209209- Marshal.from_bytes marshaled_message 0
210210- in
211211- let res =
212212- match action with
213213- | Complete_prefix (source, position) ->
214214- let source = Msource.make source in
215215- begin match Completion.at_pos source position with
216216- | Some (from, to_, compl) ->
217217- let entries = compl.entries in
218218- Protocol.Completions { from; to_; entries; }
219219- | None ->
220220- Protocol.Completions { from = 0; to_ = 0; entries = []; }
221221- end
222222- | Type_enclosing (source, position) ->
223223- let source = Msource.make source in
224224- let query = Query_protocol.Type_enclosing (None, position, None) in
225225- Protocol.Typed_enclosings (dispatch source query)
226226- | Protocol.All_errors source ->
227227- let source = Msource.make source in
228228- let query = Query_protocol.Errors {
229229- lexing = true;
230230- parsing = true;
231231- typing = true;
232232- }
207207+let on_message = function
208208+ | Protocol.Complete_prefix (source, position) ->
209209+ let source = Msource.make source in
210210+ begin match Completion.at_pos source position with
211211+ | Some (from, to_, compl) ->
212212+ let entries = compl.entries in
213213+ Protocol.Completions { from; to_; entries; }
214214+ | None ->
215215+ Protocol.Completions { from = 0; to_ = 0; entries = []; }
216216+ end
217217+ | Type_enclosing (source, position) ->
218218+ let source = Msource.make source in
219219+ let query = Query_protocol.Type_enclosing (None, position, None) in
220220+ Protocol.Typed_enclosings (dispatch source query)
221221+ | Protocol.All_errors source ->
222222+ let source = Msource.make source in
223223+ let query = Query_protocol.Errors {
224224+ lexing = true;
225225+ parsing = true;
226226+ typing = true;
227227+ }
228228+ in
229229+ let errors =
230230+ dispatch source query
231231+ |> List.map ~f:(fun (Location.{kind; main=_ ; sub; source; _} as error) ->
232232+ let of_sub sub =
233233+ Location.print_sub_msg Format.str_formatter sub;
234234+ String.trim (Format.flush_str_formatter ())
233235 in
234234- let errors =
235235- dispatch source query
236236- |> List.map ~f:(fun (Location.{kind; main=_ ; sub; source; _} as error) ->
237237- let of_sub sub =
238238- Location.print_sub_msg Format.str_formatter sub;
239239- String.trim (Format.flush_str_formatter ())
240240- in
241241- let loc = Location.loc_of_report error in
242242- let main =
243243- Format.asprintf "@[%a@]" Location.print_main error |> String.trim
244244- in
245245- Protocol.{
246246- kind;
247247- loc;
248248- main;
249249- sub = List.map ~f:of_sub sub;
250250- source;
251251- })
236236+ let loc = Location.loc_of_report error in
237237+ let main =
238238+ Format.asprintf "@[%a@]" Location.print_main error |> String.trim
252239 in
253253- Protocol.Errors errors
254254- | Add_cmis cmis ->
255255- add_cmis cmis
256256- in
257257- let res = Marshal.to_bytes res [] in
258258- Js_of_ocaml.Worker.post_message res
240240+ Protocol.{
241241+ kind;
242242+ loc;
243243+ main;
244244+ sub = List.map ~f:of_sub sub;
245245+ source;
246246+ })
247247+ in
248248+ Protocol.Errors errors
249249+ | Add_cmis cmis ->
250250+ add_cmis cmis
259251260252let run () =
261261- Js_of_ocaml.Worker.set_onmessage on_message
253253+ Js_of_ocaml.Worker.set_onmessage @@ fun marshaled_message ->
254254+ let action : Protocol.action = Marshal.from_bytes marshaled_message 0 in
255255+ let res = on_message action in
256256+ let res = Marshal.to_bytes res [] in
257257+ Js_of_ocaml.Worker.post_message res
+1
src/worker/worker.mli
···11+val on_message : Protocol.action -> Protocol.answer
12val run : unit -> unit