Nvim + merlin in wasm?

I am aware of the amazing work at GitHub - patricoferris/try-eio: Try OCaml Effects and Eio in your browser with codemirror + merlin-js.
I am also aware of the related: GitHub - rhysd/vim.wasm: Vim editor ported to WebAssembly

Wasm32 has a limitation of 4GB / thread. I think that’s more than enough to run neovim + merlin right? (No comment on emacs).

I’m wondering if anyone is working on something where it is possible to run neovim + merlin , both compiled to wasm32, inside a browser.

I am interested in the possibility of an inbrowser-ide, where we fake a filesystem as HashMap<file_name: string, contents: string>, edit this via neovim + plugins, index over this using merlin, then able to compile it (in webworker) by jsoo/parts-of-try-eio.

The end product is something like try-eio, with the following differences:

  1. replace code-mirror + merlin-js w/ [neovim + merlin + plugins]: all compiled to wasm

  2. instead of a single file, fake a fs with Hashmap<file_name: string, contents: string>


@patricoferris : If you have time, I’m also curious to hear your thoughts. Is the current try-eio/merlin-js easily extensible to handling multiple files (i.e. HashMap<file_name: string, contents: string>) instead of a single file ?

I don’t think so, the top-level is quite different to compiling programs and it wouldn’t know by itself how to look at the filesystem and load the modules in a correct order iiuc. Furthermore, the top-level is stateful too in that evaluating the files again will happen in the context of the previous evaluations. This could lead to a very confusing experience for users that you might be trying to convince are not using the top-level. I also don’t know the state of OCaml → WASM.

All that being said, I’d like to add that jsoo creates a fake filesystem that all of the file-system-manipulating functions use, so for example you can do the following:

(* Part of Sys_js if you had that in the top-level *)
external create_file : name:string -> content:string -> unit = "caml_create_file"

(* You'll actually only want to run this once, or externally as part of your app *)
let () = create_file ~name:"hello.ml" ~content:{| let msg = "Hello World" |};;

(* Load it in *)
#mod_use "hello.ml";;

let () = print_endline Hello.msg

I don’t think I phrased this question correctly. Let us take a step back, suppose we have, in the browser, the following hashmap

  let foo_bar (x: ...) = ... ;;
  let foo_cat (x: ...) (y: ...) = ... ;;

main.ml <-- file code_mirror is editing

Now, CodeMirror is editing main.ml . Suppose we type in let _ = foo_<TAB> at this point, is it possible to get merlin-js to auto complete “foo_bar” and “foo_cat” ?

If so, we can extend the CodeMirror editor into a “multi file editor”.
If not, I’m interested in understanding what merlin-js threw away (since merlin can handle multiple files).

[This is ignoring evaluation for now; just purely concerned with autocompletion, and possibly goto-def.]


Ah okay, I think you essentially still have the same problem. Merlin-js is a code-mirror extension which afaict uses the state of the current document (single editor) e.g. merlin-js/merlin_codemirror.ml at 85495ae4dd11a5e4f40d6eddd5b63a6f5ab2d820 · tmattio/merlin-js · GitHub so presumably you would have to trick code-mirror into thinking it was a single file by concatenating them together maybe?

It appears I misunderstood merlin-js as well.

In the past, I believe merlin-js was a PORT of merlin, so it works with jsoo.

However, upon further investigation, it appears:

  1. merlin-js is < 400 lines of OCaml
  2. it uses `‘merlin’ as a dep

This, is the actual situation the following:

merlin-lib compiles unmodified with jsoo
merlin-js is really a thin layer for codemirror <-> meroin-js <-> merlin-lib communication ?

@patricoferris :

Also, in a recursive clone of try-eio, we have:

brr  docs  dune  dune-project  js_of_ocaml  jsoo-code-mirror  js_top_worker  LICENSE  merlin-js  README.md  src  try-eio.opam

jsoo-code-mirror, js_top_worker, merlin-js, and src all seem readable

js_of_ocaml is huge; can this work with a standard jsoo, or do I need that particular version of jsoo (due to some required patch) ?


@patricoferris :

I just got try-eio to build, preparing to make changes to it.

However, when I run the builtin example, the (in browser repl) displays an error of:

 OCaml version 5.0.0
     Compiled with Js_of_ocaml version 5.0.1

Exception: Failure "Effect handlers are not supported".

Everything else appears to work. For example, if I eval

let x = 1 + 2;;

it displays:

val x : int = 3

I realize this is not much. Any advice on how to debug this ?

@patricoferris :

I have previously used GitHub - replit/codemirror-vim: Vim keybindings for CM6 , which is a very nice set of VIM bindings.

I am trying to inject these into the try-eio codemirror editor.

I see jsoo-code-mirror/includes.js at bd1d3c68a23655cd667986aef48c05a6514fd194 · patricoferris/jsoo-code-mirror · GitHub but it is not obvious if the coded can be injected here, or if the VIM initialization needs to be done in OCaml code.

How would you recommend I do this ? Thanks!

I think we’re losing track of the discussion in this thread a little do you want to open the questions as issues on the repos that they relate to? (E.g. Nvim + merlin in wasm? - #7 by zeroexcuses doesn’t have much to do with nvim, merlin or wasm :)) ) – happy to answer and help over there.

1 Like

Good call. Moving things over.