null-ls is archived, what now?
As of August 11th, 2023, the Neovim community lost a beloved plugin, null-ls.
If you are not familiar with null-ls, it was an incredible Neovim plugin that made it possible for non-LSP sources to hook into the LSP client in Neovim and provide standardized diagnostics and functionality. People typically used it to handle linting, formatting, and hover/completion tools when an LSP either did not provide them or when the community around a language use a different standard.
Many developers are struggling to come to terms with this transition because null-ls was such a beloved plugin that simplified our configuration experience. I'm here to give three options for a path forward if you use null-ls and are looking for outside opinions on what you should do next with your neovim config.
1. Do Nothing
null-ls is only archived, it is not broken. It seems like many open source projects and config-heavy-engineers are simply leaving null-ls in place until it eventually breaks.
I think this is a great strategy and ideal for most people, especially if you are using a neovim distribution like LazyVim. Let the maintainers handle the migration process when it is needed, and just hang out until something breaks. It's likely that null-ls will continue working just fine for a long time and will only break in a large, advertised, update to Neovim core.
2. Other Tools
Some projects are using a combination of formatter.nvim and nvim lint to piece together the tools they used via null-ls. I think this is a valid approach, and it is exciting to see these other plugins welcome the null-ls community and adapt to their needs. If you primarily care about getting stuff working quickly, this may be for you.
3. EFM
Personally, I was not happy with either of the above solutions so I went looking for something that actually replicated null-ls' approach to using tools.
efm-languageserver is a general purpose language server that can run arbitrary tools in response to language server commands. While null-ls simulated an LSP, EFM actually is an lsp that you can configure to hook into specific tools depending on filetype.
This was the solution I had been looking for, so I set it up in my dotfiles.
Here is a sample of the configuration
local defaults = require('jollyjerr.lsp')
local prettier = {
formatCommand = 'prettierd "${INPUT}"',
formatStdin = true,
}
local stylua = {
formatCommand = 'stylua',
formatStdin = true,
rootMarkers = { 'stylua.toml', '.stylua.toml' },
}
require('lspconfig').efm.setup({
init_options = { documentFormatting = true },
rootMarkers = { '.git/' },
settings = {
languages = {
lua = { stylua },
typescript = { prettier },
typescriptreact = { prettier },
javascript = { prettier },
javascriptreact = { prettier },
svelte = { prettier },
vue = { prettier },
markdown = { prettier },
html = { stylua },
},
},
on_attach = defaults.on_attach,
capabilities = defaults.get_capabilities(),
})
lspconfig.eslint.setup({
on_attach = function()
maps.nmap('<leader>EE', ':EslintFixAll<cr>')
end,
capabilities = defaults.get_capabilities(),
})
As you can see, I set up lua and javascript formatting via EFM and used
the vscode-eslint language server to handle linting. I also prefer prettierd
over prettier
as the process stays alive and you do not have to wait for
startup time when formatting.
The Bad News
null-ls was a truly unique plugin, and even with an EFM setup some users report feeling a little delay while waiting for their command to jump all the way to EFM and back. Personally I have found it to be just as fast as null-ls, but I know the projects original goal was to improve performance by removing the need for an external process.
I hope this blog was helpful! Cheers