···6666 match data with
6767 | Protocol.Typed_enclosings l -> l
6868 | _ -> assert false
6969+7070+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 false
+11-2
src/extension/merlin_codemirror.ml
···7979let ocaml = Jv.get Jv.global "__CM__mllike" |> Stream.Language.of_jv
8080let ocaml = Stream.Language.define ocaml
81818282-module Make (Config : sig val worker_url : string end) = struct
8383- let worker = Merlin_client.make_worker Config.worker_url
8282+module type Config = sig
8383+ val worker_url : string
8484+ val cmis : Protocol.cmis
8585+end
8686+8787+module Make (Config : Config) = struct
8888+ let worker =
8989+ let worker = Merlin_client.make_worker Config.worker_url in
9090+ let _ = Merlin_client.add_cmis worker Config.cmis in
9191+ worker
9292+8493 let autocomplete = autocomplete worker
8594 let tooltip_on_hover = tooltip_on_hover worker
8695 let linter = Lint.create (linter worker)
+6-1
src/extension/merlin_codemirror.mli
···66val ocaml : Code_mirror.Extension.t
77(** An extension providing OCaml syntax highlighting *)
8899-module Make : functor (Config : sig val worker_url : string end) -> sig
99+module type Config = sig
1010+ val worker_url : string
1111+ val cmis : Protocol.cmis
1212+end
1313+1414+module Make : functor (Config : Config) -> sig
1015 val autocomplete : Code_mirror.Extension.t
1116 (** An extension providing completions when typing *)
1217
+7
src/protocol/protocol.ml
···3344type source = string
5566+type cmis = {
77+ static_cmis : (string * string) list;
88+ cmi_urls : string list
99+}
1010+611type action =
712 | Complete_prefix of source * Msource.position
813 | Type_enclosing of source * Msource.position
914 | All_errors of source
1515+ | Add_cmis of cmis
10161117type error = {
1218 kind : Location.report_kind;
···3137 | Completions of completions
3238 | Typed_enclosings of
3339 (Location.t * [ `Index of int | `String of string ] * is_tail_position) list
4040+ | Added_cmis
34413542let report_source_to_string = function
3643 | Location.Lexer -> "lexer"
···33open Merlin_kernel
44module Location = Ocaml_parsing.Location
5566+let sync_get url =
77+ let open Js_of_ocaml in
88+ let x = XmlHttpRequest.create () in
99+ x##.responseType := Js.string "arraybuffer";
1010+ x##_open (Js.string "GET") (Js.string url) Js._false;
1111+ x##send Js.null;
1212+ match x##.status with
1313+ | 200 ->
1414+ Js.Opt.case
1515+ (File.CoerceTo.arrayBuffer x##.response)
1616+ (fun () ->
1717+ Firebug.console##log (Js.string "Failed to receive file");
1818+ None)
1919+ (fun b -> Some (Typed_array.String.of_arrayBuffer b))
2020+ | _ -> None
2121+2222+type signature = Ocaml_typing.Types.signature_item list
2323+type flags = Ocaml_typing.Cmi_format.pers_flags list
2424+type header = string * signature
2525+type crcs = (string * Digest.t option) list
2626+2727+(** The following two functions are taken from cmi_format.ml in
2828+ the compiler, but changed to work on bytes rather than input
2929+ channels *)
3030+let input_cmi str =
3131+ let offset = 0 in
3232+ let (name, sign) = (Marshal.from_bytes str offset : header) in
3333+ let offset = offset + Marshal.total_size str offset in
3434+ let crcs = (Marshal.from_bytes str offset : crcs) in
3535+ let offset = offset + Marshal.total_size str offset in
3636+ let flags = (Marshal.from_bytes str offset : flags) in
3737+ {
3838+ Ocaml_typing.Cmi_format.cmi_name = name;
3939+ cmi_sign = sign;
4040+ cmi_crcs = crcs;
4141+ cmi_flags = flags;
4242+ }
4343+4444+let read_cmi filename str =
4545+ let magic = Ocaml_utils.Config.cmi_magic_number in
4646+ let magic_len = String.length magic in
4747+ let buffer = Bytes.sub str 0 magic_len in
4848+ (if buffer <> Bytes.of_string magic then
4949+ let pre_len = String.length magic - 3 in
5050+ if
5151+ Bytes.sub buffer 0 pre_len
5252+ = Bytes.of_string @@ String.sub magic ~pos:0 ~len:pre_len
5353+ then
5454+ let msg =
5555+ if buffer < Bytes.of_string magic then "an older"
5656+ else "a newer"
5757+ in
5858+ raise (Ocaml_typing.Magic_numbers.Cmi.Error (Wrong_version_interface (filename, msg)))
5959+ else raise (Ocaml_typing.Magic_numbers.Cmi.Error (Not_an_interface filename)));
6060+ input_cmi (Bytes.sub str magic_len (Bytes.length str - magic_len))
6161+6262+let memoize f =
6363+ let memo = Hashtbl.create 10 in
6464+ fun x ->
6565+ match Hashtbl.find_opt memo x with
6666+ | Some x -> x
6767+ | None ->
6868+ let result = f x in
6969+ Hashtbl.replace memo x result;
7070+ result
7171+7272+let add_cmis cmi_urls =
7373+ let cmi_files =
7474+ List.map
7575+ ~f:(fun cmi -> (Filename.basename cmi |> Filename.chop_extension, cmi))
7676+ cmi_urls
7777+ in
7878+ let open Ocaml_typing.Persistent_env.Persistent_signature in
7979+ let old_loader = !load in
8080+ let fetch = memoize
8181+ (fun unit_name ->
8282+ let open Option.Infix in
8383+ List.assoc_opt (String.uncapitalize_ascii unit_name) cmi_files >>= sync_get >>| Bytes.of_string)
8484+ in
8585+ let new_load ~unit_name =
8686+ match fetch unit_name with
8787+ | Some x ->
8888+ Some {
8989+ filename = Sys.executable_name;
9090+ cmi = read_cmi unit_name x;
9191+ }
9292+ | _ -> old_loader ~unit_name
9393+ in
9494+ load := new_load
9595+9696+ let add_cmis { Protocol.static_cmis; cmi_urls } =
9797+ List.iter static_cmis ~f:(fun ( path, content) ->
9898+ let name = Filename.(concat "/static/stdlib" (basename path)) in
9999+ Js_of_ocaml.Sys_js.create_file ~name ~content);
100100+ add_cmis cmi_urls;
101101+ Protocol.Added_cmis
102102+6103let config =
7104 let initial = Mconfig.initial in
8105 { initial with
···174271 })
175272 in
176273 Protocol.Errors errors
274274+ | Add_cmis cmis ->
275275+ add_cmis cmis
177276 in
178277 let res = Marshal.to_bytes res [] in
179278 Js_of_ocaml.Worker.post_message res
180279181181-182280let run () =
183183- (* Load the CMIs into the pseudo file-system *)
184184- (* This add roughly 3mo to the final script. These could be loaded dynamically
185185- after the worker *)
186186- List.iter Static_files.stdlib_cmis ~f:(fun ( path, content) ->
187187- let name = Filename.(concat "/static/stdlib" (basename path)) in
188188- Js_of_ocaml.Sys_js.create_file ~name ~content);
189281 Js_of_ocaml.Worker.set_onmessage on_message