Transitioning to ocaml-lsp-server in emacs from merlin

Hello,

I’ve been using merlin directly in emacs for a long time and decided to try out ocaml-lsp-server with lsp-mode in Emacs. I’ve got it mostly going, however it’s not finding any modules that are not in the ocaml standard library as far as I can tell, everything appears undefined. I looked at the the log with the server and I see:

“message”: “Unbound module CCMap\nHint: Did you mean Map?”,

I have a .merlin file that specifies I am using containers. I’m not sure how ocamllsp is meant to discover these things?

My project layout is:

<ROOT>/code/.merlin
<ROOT>/code/src/foo/foo.ml
<ROOT>/code/build/release/foo/...

All of this has worked when directly using merlin so I’m curious what I’m missing to get the LSP stuff working.

Thank you

The latest ocamllsp versions do not use .merlin files, they rely on dune-merlin integration. In other words, as soon as you build your project with dune, ocamllsp gets information about modules your project uses. Due to this reliance on builds, it’s advised to build in watching mode during development to get nicer ocamllsp experience. Does that help?

1 Like

What are my options if I’m not using dune, then?

Adding dune files to describe your build shouldn’t be much more effort than writing a .merlin file. You should consider having dune files at least for development. Otherwise, the only other option is to go back to merlin.

To clarify, since I’m not using dune, are you saying to make a dune file to describe the ocaml-portions of my build even if I’m not using dune to build my repository?

That’s exactly what I suggest. The OCaml compiler does the same thing as well for example.

1 Like

Thank you. I’ll look at the ocaml compiler for tips. Do I have to do anything after making the dune file or should having the file there resolve things?

There’s probably easier examples to be found than the compiler. The compiler build is quite complex.

Once you write the dune files, build the project with dune and you should be good to go.

Wait, so I DO need to build the project with dune? I thought I didn’t need to? The situation I’m in is I have a mono-repo that is older than dune and has multiple languages with some build directories dependent on each other, so my build is quite complex. Maybe one day I’ll switch to dune but I just don’t have the bandwidth to actually get this building successfully under dune.

But if you are using emacs, is there any advantages of using ocaml-lsp-server ?

I vaguely remember that using merlin actually gave you better support for certain things due to limitations in the lsp-server protocol.

1 Like

That’s what I’m actually trying to find out. merlin, for me, is pretty slow with my personal repository and I wanted to evaluate if ocaml-lsp was better.

Ecosystem-wise, unifying my various languages under lsp-mode seems compelling. If I’m stuck with merlin then that’s fine. although at this point I suppose I don’t know how long that will last.

<frustration>I appreciate all the great work that is being done by everyone to improve the ocaml ecosystem, but by Dune’s own website, not even a majority of packages in opam use it, so making it a hard-dependency of ocaml-lsp, with no escape hatch, is frustrating</frustration>

Again, thank you, everyone, for the great work and contributions.

You need the build to succeed up to the point where the cmi’s are produced. So no, you don’t need to port your entire project.

1 Like

And those cmi’s need to be produced via dune? There is no way to implement the interface ocaml-lsp is expecting and just pass it the files I’m already building?

I don’t recall what the dune website says, but I’d be very much surprised if the majority of packages don’t use dune. And if you look at the recently released stuff, it’s all dune apart from a few small exceptions.

I under your frustration but at the end of the day, our resources are finite and we need to prioritize things. Building projects with dune is generally super easy, and manually written .merlin files are super error prone. I deemed it to be an acceptable workaround for this somewhat unpleasant situation.

If you want to go down this route, there’s a protocol that lsp speaks to dune. I suppose you could write your own binary that will tell lsp where all the artifacts are located using this protocol. Seems like a lot of more work than just getting a dev dune build running.

According to the dune website, roughly 40% of packages use it.

I appreciate all the work you’ve done and the desire to minimize user error. For me, it’s just a heavy burden to learn a tool that does what I’m already doing for a different tool that I want. It’d be great to have a “use at your own risk” option. (I’m actually generating my .merlin file automatically). I have merlin still that I can use until I have the time to learn enough dune to accomplish this. Thank you.

Yes, there’s enough workarounds available for now in my opinion. The only subset of users that must use dune are those that use new editors like vscode, sublime. I have a feeling that this subset of users isn’t particularly interested in using alternative build systems anyway.

I am curious of what you mean by “slow” and if you have some public project we could checkout to experience it?

The lsp mode for Emacs will be restricted to the non-ocaml-specific, vanilla set of LSP protocol actions so it will lacks features compared with the offical Merlin mode. (Depending on the specific performance issue it might also not solve them since it still uses Merlin as a backend.)

1 Like

Sorry I don’t have a public repo. But, for example, when I start typing an identifier, my buffer can lock up for 1-2 seconds as it pops up the possible completions. Perhaps there is something up in my emacs config? I can try to investigate that.

I’ve had the same experience with merlin. In this file, for example, it can lock up for 5-10 seconds in some cases.

I’m also considering if I should try out ocamllsp to remedy this.