Reload `init.lua` and all `require`d scripts

I can do :source $MYVIMRC to successfully reload my init.lua from in a running nvim instance, however, any files that are included with require or pcall(require, fname) do not seem to want to reload. Is there a way of doing this?

1 Like

See Programming in Lua : 8.1, especially the part about _LOADED.

1 Like

That sounds like the solution, but when I look at _LOADED the table itself seems to be null, even after my entire init.lua has run… is there some other trick I am missing to access it?

Googling around makes me think it’s package.loaded.

“This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.”

1 Like

Ah yeah, that’s always a footgun, although I really like that book :slight_smile: I found it a reference to package.loaded in the neovim docs, though: Nvim documentation: lua, first code sample.

Where do you see that? I get zero hits for _LOADED under that link.

I found the need/possibility to use package.loaded under that link. First code sample:

    :lua print(vim.inspect(package.loaded))

Granted, the link went to the wrong tag, I’ve fixed it now :wink:

Oh, right, then I misunderstood – I thought “it” in your third comment referred to what you suggested in your first comment :wink:

Rereading my post, I definitely see why you would think that :smiley: Oh well…

That is because in lua once a module is required it is then cached for the entirety of the runtime, so sourcing just $MYVIMRC isn’t enough to reload all the modules that are required inside your init.lua.

What you need to do is set those loaded modules to nil and then finally source your init.lua, and on the next re-source it will re-require the file instead of the cached one.

I stole this code from plenary and simplified it for my use case but the concept is the same. You want to make sure all your lua files are scoped within a namespace, what this means is to have all your lua files inside lua/<namespace> where (in my case I use my username: cnull) is the name of the directory, and then match all the modules that start with the namespace and set them to nil. Below is the code along with a keymap and command you can set. Just replace the pattern in name:match() from cnull to your namespace.

function _G.ReloadConfig()
  for name,_ in pairs(package.loaded) do
    if name:match('^cnull') then
      package.loaded[name] = nil
    end
  end

  dofile(vim.env.MYVIMRC)
end

vim.api.nvim_set_keymap('n', '<Leader>vs', '<Cmd>lua ReloadConfig()<CR>', { silent = true, noremap = true })
vim.cmd('command! ReloadConfig lua ReloadConfig()')

If you want to use plenary to reload instead, then you just need to require it and give it the modulename aka your namespace/directory name.

require("plenary.reload").reload_module("cnull") -- replace with your own namespace
7 Likes

Rather amazingly, I still can’t seem to find a fully satisfactory solution to this problem. package.loaded returns a seemingly arbitrary subset of the loaded files. I have yet to find a list anywhere that contains the explicit or implicit names of files loaded within my init.lua. Rather frustrating as you’d think this would be among the first things they’d have tried when developing the init.lua functionality.

Maybe you could post a minimal example for what you tried and what didn’t work? If you’re sure it doesn’t work the expected way you could open an issue, it might at least be a documentation problem.

Not sure why you would want to check for all the loaded files, since the only files that needed to be reloaded would be your own config. At this point unfortunately, you will have to re-source the way I mentioned or via plenary of you have files inside lua/ directory in your user config.

But if you insist, then you can always debug with the print command and vim.inspect and see the output is. In this case, running in nvim:

:lua print(vim.inspect(package.loaded, { depth = 1 }))

Will print out all the packages/modules loaded from nvim and your init.lua.

Now to know EXACTLY which packages were loaded from your init.lua? Well… you can always look into your init.lua file and grep for all the require code that’s in there.

I have improved the reload function by saving the hlsearch status and restoring after reloading:

function _G.ReloadConfig()
    local hls_status = vim.v.hlsearch
    for name,_ in pairs(package.loaded) do
    if name:match('^cnull') then
      package.loaded[name] = nil
    end
  end

  dofile(vim.env.MYVIMRC)
    if hls_status == 0 then
        vim.opt.hlsearch = false
    end
end

Now my improvement works, which means if your hlsearch is enabled it will be enabled on ReloadConfig() otherwise it will not. The secret is getting the value of vim.v.hlsearch.

There were a typo, sorry guys!

1 Like

I am a new neovim user, so i guess my solution may not work for some edge cases.
This function flushes the module of current buffer.

Flush = function()
    local s = vim.api.nvim_buf_get_name(0)
    if string.match(s, '^' .. cfg .. '*') == nil then
        print('fuck')
        return
    end
    s = string.sub(s, 6 + string.len(cfg), -5)
    local val = string.gsub(s, '%/', '.')
	package.loaded[val] = nil
end

You can call it whenever you write to a buffer.

autocmd BufWrite *.lua,*vim call v:lua.Flush()

This way, after you execute :source $MYVIMRC it will also reload changed lua module

Maybe you can write a wrapper around require that first checks for and removes the file from package.loaded if it appears there. I could use something like that myself.

How can I change this function to put it inside my ~/.config/nvim/lua/utils.lua ?

I wan to call it like this:

vim.cmd('command! ReloadConfig lua require('utils').reloadconfig()')

You want to make it lua module, so instead of _G you do M and return that variable M:

-- utils.lua
local M = {}

function M.reloadconfig()
  -- ...
end

return M

And the command should work.

1 Like