Logo

Developer Blog

Anton Lijcklama à Nijeholt

Dedicated to cultivating engaging and supportive engineering cultures.

404 - Netrw Not Found

My Neovim configuration and dotfiles follow at least four principles I use in my career as a software engineer:

Today, I want to focus on the last part as something suddenly broke in my Neovim setup and I had to backtrack to get to the bottom of it. Sharing this knowledge is part of the joy I get working in the field of IT.

Git must be the de facto standard by now. At this time of writing, statistics show that 77% of all the repositories are created with git. I’ve yet to work for a client that didn’t use git. Within Neovim I use quite a variety of plugins to deal with git: neogit, vim-fugitive, gitsigns, git-conflict and a bunch of others. When remotely communicating with colleagues it’s sometimes useful to send a link, highlighting a piece of code on GitHub. This neat feature is supported by vim-fugitive. You can create a visual selection, execute :GBrowse, and your default browser will be opened automatically. Redirecting you straight to GitHub and showing you the file and it’s selection. It cannot get much quicker or simpler than this! However, to my surprise this no longer worked today. I was greeted with the error Netrw not found. Define your own :Browse to use :GBrowse.

As I’m not writing unit tests for my setup, sometimes things break over time without me realising. But how did this suddenly stop working? Doesn’t netrw come out-of-the-box with Neovim? Let’s try running :Explore, as this should open the default Neovim’s file explorer. Instead of showing the file explorer I’m greeted with the error E492: Not an editor command: Explore. It indeed seems I can no longer use :Explore or its alias :Ex. Could it be there’s a plugin intervening with netrw? To make a long story short: Yes! It took a simple binary search to find the trouble maker. In my case it was oil.nvim. When installed it becomes the default file explorer, but that also intervenes with plugins relying on netrw. The fix for me was dead simple, I no longer allow it to become the default file explorer as I only use it occasionally anyway:

json
{
  "stevearc/oil.nvim",
  opts = {
    default_file_explorer = false
  },
  -- Optional dependencies
  dependencies = { "nvim-tree/nvim-web-devicons" },
},

If you do want to keep oil.nvim as your default file explorer, you can easily create a user command for :Browse as follows:

lua
vim.api.nvim_create_user_command("Browse", function(opts)
  vim.fn.system { "open", opts.fargs[1] }
end, { nargs = 1 })

As I’m using lazy.nvim, I decided to create the user command in the init function of the vim-fugitive block:

json
{
  "tpope/vim-fugitive",
  lazy = true,
  keys = {
    { "<leader>gs", ":Git<cr>", desc = "[g]it [s]tatus" },
    { "<leader>gd", ":Git diff<cr>", desc = "[g]it [d]iff" },
    { "<leader>gb", ":Git blame<cr>", desc = "[g]it [b]lame" },
    { "<leader>gB", ":GBrowse<cr>", desc = "[g]it [B]rowse", mode = { "n", "o", "x" } },
    { "<leader>gl", ":GcLog<cr>", desc = "[g]it [l]og" },
  },
  init = function()
    -- The Browse user command is needed for :GBrowse as oil.nvim is by
    -- default set as the default file explorer. Without it you'll run into
    -- the error: Netrw not found. Define your own :Browse to use :GBrowse
    vim.api.nvim_create_user_command("Browse", function(opts)
      vim.fn.system { "open", opts.fargs[1] }
    end, { nargs = 1 })
  end,
},

There are three advantages I’d like to highlight:

  • The creation of the user command is close, or actually in the code that sets up vim-fugitive. There’s no way to accidentally remove it and the comment makes it clear why this user command needs to be created.
  • vim-fugitive is fully lazy loaded (see screenshot below). However, the creation of the :Browse command is accessible even though the plugin itself has not yet been loaded. How? Because the init function is called for all plugins, even plugins that haven’t been loaded by lazy.nvim yet.

Conclusion #

It can be quite fun to investigate a problem. Especially once you understand what the problem was all about. These are the things I learned today:

  • oil.nvim disables netrw by default.
  • The init function of a lazy.nvim package is always invoked. Even if the plugin itself has not been loaded yet.
  • The config function of a lazy.nvim package is only called if the plugin is being loaded.

Posted on Jul 2, 2024 (updated on Jul 5, 2024)