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.