Using ocaml-lsp-server with opam switches in neovim

I was using a single global opam switch for multiple Ocaml projects and things were going well – but then suddenly when I installed some package a bunch of other packages were removed.

So I decided to try creating a different opam switch for each project.

But now all projects are broken because ocaml-lsp-server (ocamllsp on neovim) doesn’t pick the packages for the currently active opam switch, apparently it tries to use the default one (?) so everything is always red all the time and pretty much useless.

How should I proceed here?

This is what I do:

  1. Create a switch per project, thus keeping them separated
  2. Install ocaml-lsp-server per switch
  3. Launch neovim from the folder (thus it is launched with the configuration of the switch)

I use direnv and then for each project have a local opam switch, the .envrc (direnv config) looks like this:

export OPAMSWITCH="$PWD"
eval $(opam env)

this makes sure the executables installed in the switch are on PATH and thus launching neovim (or any other editor) from the directory will find the correct ocamllsp executable.

Thank you, but I don’t get it, that’s what I was trying and it is not working. I just tried again now and this is what happens:

This neovim instance was launched from the directory I had the switch on, and in fact I ran the following commands from a terminal launched inside the same neovim instance:

~> opam install ocamlformat ocaml-lsp-server
[NOTE] Package ocaml-lsp-server is already installed (current version is 1.17.0).
[NOTE] Package ocamlformat is already installed (current version is 0.26.1).
~> opam install
~> echo $OPAMSWITCH
/home/ad/code/cassis
~> opam install bigstringaf stdint
which ocamll[NOTE] Package stdint is already installed (current version is 0.7.2).
[NOTE] Package bigstringaf is already installed (current version is 0.9.1).
~> which ocamllsp
/home/ad/code/cassis/_opam/bin/ocamllsp
~> which ocamlc
/home/ad/code/cassis/_opam/bin/ocamlc

And yet nothing works.

Is there a way to check what opam switch ocamllsp is using or tell it to use the current one or something like that?

My neovim config just setups the default 'ocamllsp' config with 'lspconfig'.

Run $ opam switch to see what switch you are currently using.

➜  ~ opam switch
#  switch                                     compiler                    description
   /Users/owen/programming/ocaml/fooswitch    ocaml-base-compiler.4.14.2  /Users/owen/programming/ocaml/fooswitch
→  /Users/owen/programming/ocaml/barswitch    ocaml-base-compiler.5.1.1   /Users/owen/programming/ocaml/barswitch
   default                                    ocaml.5.1.0                 default

[NOTE] Current switch is set locally through the OPAMSWITCH variable.
       The current global system switch is default.

Then set the switch you want with

$ eval $(opam env --switch=<SWITCH_NAME> --set-switch)

If you are using local switches you can just use $ eval $(opam env) in the current local switch directory to set it as the current switch.

Thank you, but it makes no difference. I thought I had made clear that I was using the correct switch in the previous message:

~> opam switch
#  switch               compiler                    description
→  /home/ad/code/cassis ocaml-base-compiler.5.1.0
          /home/ad/code/cassis
   /home/ad/code/bip340 ocaml-base-compiler.4.02.0
          /home/ad/code/bip340
   default

I feel like I’m missing something very obvious.

How does neovim decides what ocamllsp to start and how does ocamllsp decides what switch to use?

nvim-lspconfig just starts the ocamllsp executable, without any explicit path specification.

Can you post the output of command -v ocamllsp and echo $PATH for further troubleshooting. Maybe there is something weird going on with the shell configuration and ocamllsp from your current switch is not the first one in the PATH.

~> command -v ocamllsp
/home/ap/code/cassis/_opam/bin/ocamllsp
~> echo $PATH
/home/ap/code/cassis/_opam/bin /home/ap/.bun/bin /home/ap/.yarn/bin /home/ap/.deno/bin /home/ap/.opam/default/bin /home/ap/.bun/bin /home/ap/.yarn/bin /home/ap/.deno/bin /usr/local/sbin /usr/local/bin /usr/bin /usr/bin/site_perl /usr/bin/vendor_perl /usr/bin/core_perl /home/ap/code/go/bin /home/ap/.nimble/bin /home/ap/.pub-cache/bin /home/ap/.cargo/bin /home/ap/npm_modules/bin /home/ap/node_modules/bin /home/ap/.local/share/coursier/bin /home/ap/.local/bin /home/ap/code/go/bin /home/ap/.nimble/bin /home/ap/.pub-cache/bin /home/ap/.cargo/bin /home/ap/npm_modules/bin /home/ap/node_modules/bin /home/ap/.local/share/coursier/bin /home/ap/.local/bin

Thanks. I’d say this looks good. Unfortunately I’ve missed that you’ve already provided the output by the which command. You can also run :LspInfo from Neovim and verify that “cmd:” shows the correct ocamllsp binary.

Just one more basic question. Did you run dune build prior to opening the file in Neovim? I usually get these kind of errors, when starting a fresh project before running build or build --watch the first time.

You must be kidding me. It was the dune build that did the trick!

And I knew that, because I also knew from experience that the LSP would complain of everything before a dune build with the new libraries and so on, but I got so tangled up with the opam switch transition that I didn’t realize this basic step was missing.

Thank you very much for your patience and help.

1 Like

Dont know if this helps anyone but I got around this by:

  • In Nvim, running :LspInfo
    • Seeing where the cmd is for the ocaml server is. Something like .~/.local/share/nvim/mason/bin/ocamllsp
    • mv that command (i just add a .disable to the end)
    • create a script in its place that has
#! /bin/sh
opam exec -- ocamllsp $1
  • make the new file executable chmod +x bin/ocamllsp
  • Restart the lsp /nvim

And now neovim is always using the opam set lsp.
This is hacky but i just need things to run quickly,