Struggles adding Brr support to try-eio / codemirror merlin auto completion

I’m trying to add support for Brr to try-eio repl / codemirror. The error I am getting is:

merlin_worker.bc.js:5482 Fatal error: exception Ocaml_typing.Persistent_env.Error(_)
MlFakeFd_out.write @ merlin_worker.bc.js:5482
caml_ml_flush @ merlin_worker.bc.js:3553
caml_ml_output_bytes @ merlin_worker.bc.js:6206
caml_ml_output @ merlin_worker.bc.js:6215
caml_ml_output_char @ merlin_worker.bc.js:6459
caml_call2 @ merlin_worker.bc.js:17686
output_acc @ merlin_worker.bc.js:21118
caml_call2 @ merlin_worker.bc.js:22538
_h_ @ merlin_worker.bc.js:22547
caml_call1 @ merlin_worker.bc.js:17683
make_printf$0 @ merlin_worker.bc.js:20416
make_printf @ merlin_worker.bc.js:20794
width @ merlin_worker.bc.js:20397
caml_call_gen @ merlin_worker.bc.js:1701
caml_call_gen @ merlin_worker.bc.js:1706
caml_call2 @ merlin_worker.bc.js:23233
default_uncaught_exception_han @ merlin_worker.bc.js:23604
caml_call2 @ merlin_worker.bc.js:23233
handle_uncaught_exception @ merlin_worker.bc.js:23628
caml_call_gen @ merlin_worker.bc.js:1701
caml_fatal_uncaught_exception @ merlin_worker.bc.js:6075
(anonymous) @ merlin_worker.bc.js:8325
error (async)
caml_setup_uncaught_exception_handler @ merlin_worker.bc.js:8321
(anonymous) @ merlin_worker.bc.js:8329
_build/default/repl/merlin_worker.bc.js @ merlin_worker.bc.js:9056
__require2 @ merlin_worker.bc.js:12
(anonymous) @ merlin_worker.bc.js:171072
(anonymous) @ merlin_worker.bc.js:171073

The way I tried to setup this up was updating dune to include brr:

(data_only_dirs stdlib brr)

(library
 (name merlin_js_worker_static)
 (modules static_files)
 (preprocess
  (pps ppx_blob))
 (preprocessor_deps
  (glob_files stdlib/*.cmi)
  (glob_files brr/*.cmi)))

(rule
 (target static_files.ml)
 (deps
  (glob_files stdlib/*.cmi)
  (glob_files brr/*.cmi))
 (action
  (run ocaml %{dep:gen_static.ml})))

and copying over relevant cmi filesinto brr/* , see:

brr/
brr/brr_ocaml_poke.cmi
brr/brr_note_legacy.cmi
brr/jstr.cmi
brr/brr_io.cmi
brr/jv.cmi
brr/fut.cmi
brr/brr_poked.cmi
brr/brr_canvas.cmi
brr/brr_ocaml_poke_ui.cmi
brr/brr_poke.cmi
brr/brr_webworkers.cmi
brr/brr_webcrypto.cmi
brr/brr_note_kit.cmi
brr/brr_note.cmi
brr/brr_webaudio.cmi
brr/brr.cmi
brr/brr_webmidi.cmi
stdlib/
stdlib/eio__core__Debug.cmi
stdlib/stdlib__String.cmi
stdlib/stdlib__Lazy.cmi
stdlib/eio__Fs.cmi
stdlib/eio__.cmi
stdlib/eio__Generic.cmi
stdlib/unix.cmi
stdlib/stdlib__Char.cmi
stdlib/stdlib__Set.cmi
stdlib/stdlib__List.cmi
stdlib/arith_status.cmi
stdlib/stdlib__Oo.cmi
stdlib/stdlib.cmi
stdlib/stdlib__Stream.cmi
stdlib/stdlib__Semaphore.cmi
stdlib/eio__core__Hook.cmi
stdlib/stdlib__Bigarray.cmi
stdlib/stdlib__Scanf.cmi
stdlib/stdlib__Float.cmi
stdlib/stdlib__Option.cmi
stdlib/stdlib__BytesLabels.cmi
stdlib/dynlink.cmi
stdlib/eio_mock__Handler.cmi
stdlib/nat.cmi
stdlib/stdlib__Weak.cmi
stdlib/stdlib__Seq.cmi
stdlib/stdlib__In_channel.cmi
stdlib/eio__Buf_write.cmi
stdlib/ratio.cmi
stdlib/stdlib__Queue.cmi
stdlib/camlinternalMod.cmi
stdlib/stdlib__ArrayLabels.cmi
stdlib/stdlib__Int32.cmi
stdlib/stdlib__Mutex.cmi
stdlib/stdlib__Result.cmi
stdlib/eio__Path.cmi
stdlib/stdlib__Array.cmi
stdlib/stdlib__Random.cmi
stdlib/eio_mock__Clock.cmi
stdlib/camlinternalFormatBasics.cmi
stdlib/eio_mock__Net.cmi
stdlib/stdlib__StdLabels.cmi
stdlib/stdlib__Either.cmi
stdlib/stdlib__Ephemeron.cmi
stdlib/stdlib__Callback.cmi
stdlib/stdlib__Printf.cmi
stdlib/profiling.cmi
stdlib/big_int.cmi
stdlib/stdlib__Marshal.cmi
stdlib/camlinternalOO.cmi
stdlib/camlinternalFormat.cmi
stdlib/eio__core__Waiters.cmi
stdlib/eio__Time.cmi
stdlib/eio__Stream.cmi
stdlib/topdirs.cmi
stdlib/stdlib__Bytes.cmi
stdlib/camlinternalAtomic.cmi
stdlib/bigarray.cmi
stdlib/stdlib__Bool.cmi
stdlib/eio__Flow.cmi
stdlib/stdlib__Condition.cmi
stdlib/stdlib__Nativeint.cmi
stdlib/eio_mock__Backend.cmi
stdlib/stdlib__Uchar.cmi
stdlib/stdlib__Obj.cmi
stdlib/stdlib__Genlex.cmi
stdlib/camlinternalLazy.cmi
stdlib/num.cmi
stdlib/eio__Semaphore.cmi
stdlib/std_exit.cmi
stdlib/eio__core__Promise.cmi
stdlib/stdlib__Map.cmi
stdlib/eio__core__Switch.cmi
stdlib/stdlib__Domain.cmi
stdlib/stdlib__Int.cmi
stdlib/eio.cmi
stdlib/stdlib__ListLabels.cmi
stdlib/eio_mock__Action.cmi
stdlib/stdlib__Arg.cmi
stdlib/stdlib__Int64.cmi
stdlib/stdlib__StringLabels.cmi
stdlib/eio__core__.cmi
stdlib/eio_mock__.cmi
stdlib/stdlib__Parsing.cmi
stdlib/stdlib__Hashtbl.cmi
stdlib/eio__core__Exn.cmi
stdlib/stdlib__Lexing.cmi
stdlib/stdlib__Fun.cmi
stdlib/stdlib__Printexc.cmi
stdlib/stdlib__Pervasives.cmi
stdlib/stdlib__Out_channel.cmi
stdlib/eio__File.cmi
stdlib/eio__Net.cmi
stdlib/str.cmi
stdlib/eio__core__Ctf.cmi
stdlib/stdlib__Digest.cmi
stdlib/eio__core__Suspend.cmi
stdlib/eio__core.cmi
stdlib/unixLabels.cmi
stdlib/eio__core__Single_waiter.cmi
stdlib/eio__Buf_read.cmi
stdlib/stdlib__Effect.cmi
stdlib/eio__Condition.cmi
stdlib/eio_mock.cmi
stdlib/eio_mock__Flow.cmi
stdlib/stdlib__Unit.cmi
stdlib/stdlib__Buffer.cmi
stdlib/eio__Domain_manager.cmi
stdlib/stdlib__Stack.cmi
stdlib/eio__Eio_mutex.cmi
stdlib/stdlib__MoreLabels.cmi
stdlib/eio__core__Cancel.cmi
stdlib/stdlib__Gc.cmi
stdlib/stdlib__Complex.cmi
stdlib/stdlib__Atomic.cmi
stdlib/stdlib__Sys.cmi
stdlib/eio__core__Fiber.cmi
stdlib/stdlib__Filename.cmi
stdlib/stdlib__Format.cmi

I am trying to figure out the next step to try in debugging this. The XY problem is I am trying to learn how to add modules to the try-eio/codemirror auto completion menu.

Thanks!

One step of progress to this would be if, on this error, we can get the merlin worker thread to catch it instead of crashing the merlin_worker thread (and losing all auto completion).

Have you updated gen_static.ml ?

Good question. It is currently commented out because I went a step further and copied brr/* into stdlib/* as it seems parts of merlin_worker has stdlib hardcoded:

#use "topfind" ;;
#require "unix";;


let rec iter_cmi ~f dir_handle =
  match Unix.readdir dir_handle with
  | exception End_of_file -> ()
  | file ->
    if Filename.extension file = ".cmi" then
      f file;
    iter_cmi ~f dir_handle

let () =
  let cwd = Unix.getcwd () in
  let out = open_out "static_files.ml" in

  Printf.fprintf out "let stdlib_cmis = [";

  let stdlib = Filename.concat cwd "stdlib" in
  let dir = Unix.opendir stdlib in
  iter_cmi ~f:(fun file ->
    let fullpath = Filename.concat stdlib file in
    Printf.fprintf out "(%S,[%%blob %S]);" fullpath fullpath) dir;

  (*
  let stdlib = Filename.concat cwd "brr" in
  let dir = Unix.opendir stdlib in
  iter_cmi ~f:(fun file ->
    let fullpath = Filename.concat stdlib file in
    Printf.fprintf out "(%S,[%%blob %S]);" fullpath fullpath) dir;
     *)

  Printf.fprintf out "]\n";

  close_out out

I think I am making progress on this. I found the right place in merlin_worker to try/catch and return empty list of completions on error – however, it appears CodeMirror is still throwing an error of its own.

I got something useful:

The files /static/stdlib/stdlib.cmi and /static/stdlib/brr.cmi\nmake inconsistent assumptions over interface Stdlib

I suspect this is because I used the *.cmi from git for stdlib, and the *.cmi from ~/.opam for brr.

In case anyone else runs into this, the ‘solution’ for me was:

cp ~/.opam/default/lib/ocaml/**/*.cmi .
cp ~/.opam/default/lib/brr/**/*.cmi .