Nvim: what is Mason?

I fell back into old habits. Earlier in the year I determined that I should be happy writing shorter pieces here. They need not be epics. And what happened? I looked back today and realised that I’d been working for two months, on and off, on a rather rambling piece about mason.nvim.

What I’d done is decide that I couldn’t just write two paragraphs about what Mason was, even if it covered all I’d wanted to know about Mason when learning nvim. Instead, it was a 500 line odyssey into the Mason code base, which ends up to be quite a trek. Not a messy one, but complex, because the Mason code base does a ton of stuff.

And in the end, doing the required drafting work to explain the code was too much. It was too much work, and I wasn’t really convinced there was much point to it. So the post got to a certain point and just sat there. I’d satisfied my itch to understand more about Mason, but I didn’t have the time to write that up in a comprehensible way.

So, instead, here’s the two eight paragraphs about Mason that I wish I’d read.

No really, what is Mason?

Mason exists to install things into an isolated execution environment that the nvim process can access. Essentially, to keep things like gopls outside your normal environment and to configure them with a setup that will work for nvim. In particular, it’s designed to pull down language servers for nvim to use.

To install packages, one can either use :MasonInstall gopls denols or use Lua code in nvim’s configuration:

require("mason").setup()
require("mason-lspconfig").setup({
    ensure_installed = { "gopls", "denols" }
})

The nice thing about using configuration is that configuration can follow your nvim around. Meaning that setting up a new machine can be done by copying in the configuration, installing the plugin and starting nvim. Mason will kick in to install your software.

Mason downloads binaries to a sub-directory of the nvim “data directory”. It uses ~/.local/share/nvim/mason on macOS. There are several folders in that directory, but the key ones are bin and packages:

/Users/mike/.local/share/nvim/mason
├── bin
│   ├── deno -> /Users/mike/.local/share/nvim/mason/packages/deno/deno
│   └── gopls -> /Users/mike/.local/share/nvim/mason/packages/gopls/gopls
├── packages
│   ├── deno
│   │   ├── deno
│   │   ├── mason-receipt.json
│   │   └── mason-schemas
│   │       └── lsp.json
│   └── gopls
│       ├── gopls
│       └── mason-receipt.json
[... other folders ...]

To make these available within the nvim environment, Mason alters the $PATH used by nvim. This can be seen by executing :echo $PATH within nvim; if I do this, my $PATH starts with the Mason bin folder:

/Users/mike/.local/share/nvim/mason/bin:/Users/mike/.asdf/shims:/usr[...]

As I said, I spent quite a lot of time following through the code from :MasonInstall onwards. It’s complex, but it works well. I missed Mason when I experimented with Helix. (I still don’t know whether I prefer nvim or helix).

Anyway, there you have it: Mason uses a bunch of smart code to manage a folder in your nvim data directory, and adds its bin directory to nvim’s $PATH. Convenience ensues.

← Older
Editor renaissance: Helix
→ Newer
Photo: Flamingos at Lagos Zoo