Neovim Setup for OCaml
Updates:
- 2025-03-22: Replace the
null-ls/none-ls
plugin withconform.nvim
for simplicity :)
Intro
In previous post, I elaborated on how to set up Neovim from scratch. However, I didn’t answer the following questions:
- What if an LSP does not support formatting, how do you configure Neovim to support a third-party code formatting tool?
- How do you change configuration files when adding a new programming language?
Recently, I started learning OCaml, and I thought it would be a good opportunity to answer these questions.
Install OCaml
It is quite handy to install OCaml on a Mac with Homebrew.
$ brew install opam
According to the output of Homebrew, we need to perform additional configurations and modify ~/.zshrc
(for Zsh users) or ~/.bashrc
(for Bash users).
$ opam init
# press `y` to confirm
To make the modifications work, run the following command in your terminal
$ source ~/.zshrc
# $ source ~/.bashrc # if you use bash
Finally, we can use this command to check if everything goes right.
$ opam switch
The output will be like
# switch compiler description
-> 5.0.0 ocaml-base-compiler.5.0.0 5.0.0
default ocaml.4.14.0 default
Similar to IPython for Python, the OCaml offers a REPL tool called utop. We can install this to practice programming OCaml.
$ opam install utop dune
Just try the utop REPL yourself :)
$ utop
The output would be like
─────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────
│ Welcome to utop version 2.13.1 (using OCaml version 5.0.0)! │
└─────────────────────────────────────────────────────────────┘
Type #utop_help for help about using utop.
─( 10:33:26 )─< command 0 >────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop #
┌──────────────┬──────────────┬───────────────┬─────┬───────────┬────┬───┬──────────┬─────┬───────────┬──────┬────────────┬───────┬───────────┬──────────────┬──────────┬────────┐
│Afl_instrument│Alias_analysis│Allocated_const│Annot│Applicative│Arch│Arg│Arg_helper│Array│ArrayLabels│Asmgen│Asmlibrarian│Asmlink│Asmpackager│Assert_failure│Ast_helper│Ast_inva│
└──────────────┴──────────────┴───────────────┴─────┴───────────┴────┴───┴──────────┴─────┴───────────┴──────┴────────────┴───────┴───────────┴──────────────┴──────────┴────────┘
OCaml LSP configurations
If you follow my previous post, then the file hierarch of your setup will be like
.
├── init.lua
└── lua
├── colorscheme.lua
├── keymaps.lua
├── lsp.lua
├── options.lua
└── plugins.lua
Previously, we leveraged mason.nvim to set up LSPs. To add LSP for OCaml:
- Open Neovim and type
:Mason
, findocaml-lsp
in the(2) LSP
section, and pressi
when the cursor stays on the line. - Open the configurations file for LSP(
lsp.lua
in my configurations), add the following Lua code
... -- rest of the configurations
lspconfig.ocamllsp.setup({
on_attach = on_attach,
})
You may have your configuration files and do not follow my previous post. Thus, only adding the aforementioned Lua code may not work for you. However, you can check the full configuration here to understand how it works and adapt to your configurations.
After modifying lsp.lua
, we can restart Neovim to make the configurations take effect.
Similar to rust-analyzer, we can only use ocaml-lsp
in a project but not a single file.
Now you can create a new dune project to see if LSP works.
OCaml Formatter configurations
The ocaml-lsp
LSP does not support formatting OCaml code. If you try to format an OCaml code, you will get an error message:
[LSP] Format request failed, no matching language servers.
Now, I will talk about how to set up a formatter for OCaml.
You may have noticed that the Mason tool also offers linters and formatters. The formatter for OCaml is ocamlformat, so we can install it just like we install an LSP.
However, ocamlformat is a CLI tool which can not be integrated into Neovim. Luckily, we have conform.nvim plugin which can do us this favor.
Open the plugins.lua
file and add the Lua codes. After saving the changes and restarting Neovim, you should see that lazy.nvim
is installing the plugin.
... -- rest of the configurations, omit for simplicity
require("lazy").setup({
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
ocaml = { "ocamlformat" },
},
formatters = {
ocamlformat = {
command = "ocamlformat",
args = {
"--if-then-else",
"vertical",
"--break-cases",
"fit-or-vertical",
"--type-decl",
"sparse",
-- $FILENAME - absolute path to the file
"$FILENAME",
},
},
},
},
}
... -- rest of the configurations, omit for simplicity
})
The code above seems to be complicated at first glance but I am sure that you will find the patterns
formatters_by_ft
- add an entry for formatterformatters
- add more configurations if needed
FAQs:
- How do I find which formatter should be used for a programming language? Type
:help conform-formatters
, search for the programming language, and you should see some options. Picking one and install it with:Mason
. - How do I add a formatter to
conform.nvim
? Add a new entry informatters_by_ft
, as shown in the example. - How do I customize a formatter? Check the official manual of the formatter.
Finally, we also need to modify the lsp.lua
file. The original lines related to code formmating look like this:
... -- rest of the configurations, omit for simplicity
vim.keymap.set("n", "<space>f", function()
vim.lsp.buf.format({ async = true })
end, bufopts)
... -- rest of the configurations, omit for simplicity
Now we are using conform.nvim
to do formatting. Thus, we need to use the format
function in conform.nvim
.
... -- rest of the configurations, omit for simplicity
vim.keymap.set("n", "<space>f", function()
require("conform").format({ async = true, lsp_fallback = true })
end, bufopts)
... -- rest of the configurations, omit for simplicity
Save the changes and restart Neovim to see if it works.
Wrap-up
Now let’s summarize how to set up Neovim for a new programming language. If you also use mason.nvim, mason-lspconfig, conform.nvim, you can follow the instructions to setup:
- Read the official pages and install the programming language’s environment on your machine.
- Open Neovim, type
:Mason
, and install the corresponding LSP. Refer to the official LSP documentation and check whether it includes a built-in formatter. If it does not, use :Mason to install one. - Open the
lsp.lua
file and configure LSP - If you install the formatter by yourself, you also need to change the configurations for
conform.nvim
.
For anything not clearly stated in this post, you can check my dotfiles configurations repo for more details.