You don’t need ‘vim-rooter’ (usually) or How to set up smart autochange of current directory
Originally posted on Reddit
Hello, Neovim users!
The airblade/vim-rooter plugin is an essential part of my Neovim workflow. It automatically changes current directory (:h current-directory
) for every buffer to a more natural one (like to path of its Git repository). For me this has the following benefits:
- Most file explorers open closer to the file of current buffer and not inside directory in which Neovim was started.
- Searching files with Telescope is more natural.
- Built-in terminal opens in directory I usually want it to open: in root based on current buffer file.
However, starting from Neovim 0.8 ‘vim-rooter’ is (almost) obsolete. Using an amazing vim.fs
module you can set up basic autochange of current directory using these lines of code (call them somewhere during your Neovim startup):
-- Array of file names indicating root directory. Modify to your liking.
local root_names = { '.git', 'Makefile' }
-- Cache to use for speed up (at cost of possibly outdated results)
local root_cache = {}
local set_root = function()
-- Get directory path to start search from
local path = vim.api.nvim_buf_get_name(0)
if path == '' then return end
path = vim.fs.dirname(path)
-- Try cache and resort to searching upward for root directory
local root = root_cache[path]
if root == nil then
local root_file = vim.fs.find(root_names, { path = path, upward = true })[1]
if root_file == nil then return end
root = vim.fs.dirname(root_file)
root_cache[path] = root
end
-- Set current directory
vim.fn.chdir(root)
end
local root_augroup = vim.api.nvim_create_augroup('MyAutoRoot', {})
vim.api.nvim_create_autocmd('BufEnter', { group = root_augroup, callback = set_root })
Of course this implementation has certain limitations: - The main one is a lack of ability to use glob patterns to find root directory. However, although solvable, I think the most common use case is to define root based on some pre-determined set of actual file names, so this shouldn’t be a big issue. - It caches results to speed up computations with a downside of result possibly being outdated. Usually not an issue, though. Remove all cache related code to not do that.
Initially I planned to make a separate ‘mini.root’ module, but realized that it would mostly be a reimplementation of vim.fs
. So instead I decided to add setup_auto_root()
function to mini.misc. If you want a more tested and documented solution, check it out and tell me what you think. Thanks!