Neovim - Project Local Config with exrc.nvim
Published on byMunif TanjimNeovim is awesome and I love it!
Why? You might ask. The answer is rather simple.
It’s awesome because I love it.
Now that we agree on that, let’s focus on the topic… Project Local Config.
Why is Project Local Config?
Usually your Neovim configuration lives in a single location: ~/.config/nvim
.
And most of the times, that’s all you need. But what if you need to change some
config only for a specific project? Maybe you want to set a different theme when
you’re working on that project… or maybe tweak the behavior of the LSP server
for that specific project.
That’s why you need project local config for Neovim. It can be done in multiple ways and I’m gonna list them all.
Modify your Neovim config file
This is the most straight-forward way of doing it. In your Neovim config file, you need check the current working directory and set the config based on that:
--[[ ~/.config/nvim/init.lua ]]local cwd = vim.fn.getcwd(-1, -1)if cwd == '/path/to/project-a' then-- config for project-aelseif cwd = '/path/to/project-b' then-- config for project-bend
Pros:
- Safe. It’s your own config.
- Supports Lua config file.
Cons:
- Config can’t be tracked with the project using
git
. - Hardcoded paths are machine dependent.
If you’re okay with this approach, you can stop here. But do continue if you want something better.
Built-in Option: exrc
This is the built-in 'exrc'
option. If enabled, Neovim will search
for the following files in the current directory:
.nvimrc
.exrc
And use the first one it finds.
Enabling it is as simple as adding this in your Neovim config:
--[[ ~/.config/nvim/init.lua ]]vim.o.exrc = true
Pros:
- Built-in feature.
- Config can be tracked with the project using
git
.
Cons:
- Deprecated (check
:help 'exrc'
). - Security risk. Config is run blindly.
- No support for Lua config file.
If you end up going with this approach, you should also enable the 'secure'
option. That will reduce the security risk of 'exrc'
option a bit.
--[[ ~/.config/nvim/init.lua ]]vim.o.secure = true
But if you want one better, the next one is for you.
Plugin: exrc.nvim
It’s the plugin that I wrote to make 'exrc'
great again. It does everything
the built-in 'exrc'
option does and then some more… and does all that safely.
You install it like any other plugin, using your plugin manager of choice. And the set it up like this:
--[[ ~/.config/nvim/init.lua ]]vim.o.exrc = falserequire("exrc").setup({files = {".nvimrc.lua",".nvimrc",".exrc.lua",".exrc",},})
Now you can add local config file for your project:
--[[ /path/to/project-a ]]print("This is awesome!")
And then, the first time you open this project, you’ll be greeted with this prompt:
If you allow it, it will run the config file and remember your choice. If the config file changes, it will show the prompt again for you to review the updated content.
Pros:
- Secure. Config is run only after you review and allow it.
- Config can be tracked with the project using
git
. - Supports Lua config file.
Cons:
- Once you use it, you can’t do without it.
Project Local LSP Settings with exrc.nvim
Now, let’s see how you can use exrc.nvim
to modify LSP settings for
a specific project.
Let’s define a helper function in Neovim’s config directory:
--[[ ~/.config/nvim/lua/config/lsp/custom.lua ]]local mod = {}---@param server_name string---@param settings_patcher fun(settings: table): tablefunction mod.patch_lsp_settings(server_name, settings_patcher)local function patch_settings(client)client.config.settings = settings_patcher(client.config.settings)client.notify("workspace/didChangeConfiguration", {settings = client.config.settings,})endlocal clients = vim.lsp.get_active_clients({ name = server_name })if #clients > 0 thenpatch_settings(clients[1])returnendvim.api.nvim_create_autocmd("LspAttach", {callback = function(args)local client = vim.lsp.get_client_by_id(args.data.client_id)if client.name == server_name thenpatch_settings(client)return trueendend,})endreturn mod
Now let’s say you want to setup Lua Language Server (a.k.a sumneko_lua
)
for Hammerspoon config directory. For that, make sure:
- LSP is set up correctly in your Neovim config.
- EmmyLua spoon is installed and loaded in your Hammerspoon config.
Next, create your project local config file in the Hammerspoon config directory
(i.e. ~/.config/hammerspoon
):
--[[ ~/.config/hammerspoon/.nvimrc.lua ]]require("config.lsp.custom").patch_lsp_settings("sumneko_lua", function(settings)settings.Lua.diagnostics.globals = { "hs", "spoon" }settings.Lua.workspace.library = {}local hammerspoon_emmpylua_annotations = vim.fn.expand("~/.config/hammerspoon/Spoons/EmmyLua.spoon/annotations")if vim.fn.isdirectory(hammerspoon_emmpylua_annotations) == 1 thentable.insert(settings.Lua.workspace.library, hammerspoon_emmpylua_annotations)endreturn settingsend)
If you open Neovim in that directory now, exrc.nvim
will run the .nvimrc.lua
file to change the settings for
sumneko_lua
to work with Hammerspoon’s APIs. 🤘🏼
That’s it for today!
You can find all the snippets here Gist: Neovim - Project Local Config with exrc.nvim.
And the plugin repository here: MunifTanjim/exrc.nvim.
Have a great day! 😃