Better Netrw - Recipes and Fixes for Vim's File Browser ✅

Published: (Updated: |   7 min read

Improve Vim's default browser and make the most out of Netrw with this collection of config snippets! Inspired by 'better bash' - These setting recipes aim to improve quality-of-life of Netrw and fix some of its bugs.


Netrw is Vim’s default file browser and can be a very light-weight and minimal solution to browsing your files. With its default settings, Netrw can be a bit daunting to understand and has a fair share of bugs too. The config recipes provided here can help you turn Netrw into a worthy contender for file browsing in Vim. With “Better Netrw” you will no longer need any external file browser plugin, all you need you already have installed and what is left to do is just a bit of configuration.

Use the table of contents to quickly find recipes relevant to you.

Note

Some recipes here are fixes to many Netrw bugs / unpolished features. They might become outdated over time, so please be aware of that when using them. I will try to keep everything here up-to-date, but it can happen that some fixes may break more stuff than they repair depending on your setup.

Basics & Recommendations

Making Netrw behave like a sidebar file drawer

Basics settings to make Netrw work like the “sidebar file viewer” in other popular IDEs. Use the command :Lexplore to toggle the sidebar. Note that using :Lexplore introduces a new bug.

vim.g.netrw_banner = 0 -- Hide the Netrw banner on top
vim.g.netrw_altv = 1 -- Create the split of the Netrw window to the left
vim.g.netrw_browse_split = 4 -- Open files in previous window. This emulates the typical "drawer" behavior
vim.g.netrw_liststyle = 4 -- Set the styling of the file list to be one column with files inside
vim.g.netrw_winsize = 14 -- Set the width of the "drawer"
let g:netrw_banner = 0 " Hide the Netrw banner on top
let g:netrw_altv = 1 " Create the split of the Netrw window to the left
let g:netrw_browse_split = 4 " Open files in previous window. This emulates the typical 'drawer' behavior
let g:netrw_liststyle = 4 " Set the styling of the file list to be one column with files inside
let g:netrw_winsize = 14 " Set the width of the 'drawer'

Warning

I heavily recommend against using vim.g.netrw_liststyle = 3 because it is quite unstable / buggy.

Make Netrw consistently open the current directory or desired root directory

The easiest way to make Netrw open in the current working directory is to set as such when you open Vim. This is done by calling the following fuction at startup:

vim.cmd(":cd %:h")
:cd %:h

For more flexibility you can add onto the :Lexplore command and easily tell Netrw whether to open the current working directory, or the directory of the file you have opened:

vim.cmd(":Lexplore %:p:h") -- Use this to open the local directory
vim.cmd(":Lexplore") -- Use this to open the root directory (CWD)
:Lexplore %:p:h " Use this to open the local directory
:Lexplore " Use this to open the root directory (CWD)

Overwrite Netrw keybindings

To utilize your own keybindings for Netrw, you will have to define them while inside the “netrw filetype”. The best approach for this is to place your keybindings inside the Netrw ftplugin:
$VIM_CONFIG/after/ftplugin/netrw.lua or
$VIM_CONFIG/after/ftplugin/netrw.vim

Be aware that some keybindings of Netrw are a bit messy and cannot be overwritten. Also make sure to check :map <key> while inside the Netrw buffer to see what commands are bound to certain keys. You can then reuse these commands in your own bindings as well.

 -- Mark files with v
vim.keymap.set("n", "v", "mf", { remap = true, buffer = true })
-- Open file/directory with double Vim direction key
vim.keymap.set("n", "ll", "<Plug>NetrwLocalBrowseCheck", { noremap = true, buffer = true })
vim.keymap.set("n", "hh", "<Plug>NetrwBrowseUpDir", { noremap = true, buffer = true })
" Mark files with v
remap <buffer> v mf
" Open file/directory with double Vim direction key
noremap <buffer> ll <Plug>NetrwLocalBrowseCheck
noremap <buffer> hh <Plug>NetrwBrowseUpDir

Add file icons to Netrw with ‘netrw.nvim’

Using the plugin Netrw.nvim, you can have Netrw look like modern file browser. The plugin adds ‘devicons’ for all relevant file types making Netrw look much more modern:

Overwrite file operations: copy, move and rename

Netrw’s file operation can be slightly counter-intuitive and glitchy. These overwrites make them more controlled by utilizing Vim’s internal file system API:

All marked files in Netrw are taken from vim.fn["netrw#Expose"]("netrwmarkfilelist"). The snippets then takes the files and performs the desired operation with more intuitive keys: yp for copy + paste, dp for cut + paste and r for simple rename.

-- Overwrite copy
vim.keymap.set("n", "yp", function()
	local target_dir = vim.b.netrw_curdir
	local file_list = vim.fn["netrw#Expose"]("netrwmarkfilelist")
	print(utils.dump_table(file_list))
	if utils.is_table(file_list) then
		for _, node in pairs(file_list) do
			vim.loop.fs_copyfile(node, target_dir .. "/" .. vim.fs.basename(node), { excl = true })
		end
	end
end, { remap = true, buffer = true })

-- Overwrite move
vim.keymap.set("n", "dp", function()
	local target_dir = vim.b.netrw_curdir
	local file_list = vim.fn["netrw#Expose"]("netrwmarkfilelist")
	print(utils.dump_table(file_list))
	if utils.is_table(file_list) then
		for _, node in pairs(file_list) do
			local file_name = vim.fs.basename(node)
			local target_exists = vim.loop.fs_access(target_dir .. "/" .. file_name, "W")
			if not target_exists then
				vim.loop.fs_rename(node, target_dir .. "/" .. file_name)
			else
				print("File '" .. file_name .. "' already exists! Skipping...")
			end
		end
	end
end, { remap = true, buffer = true })

-- Overwrite rename
vim.keymap.set("n", "r", function()
	local target_dir = vim.b.netrw_curdir
	local old_file_name = vim.fn["netrw#Call"]("NetrwGetWord")
	local new_file_name = vim.fn.input("New Name: ", old_file_name)
	if new_file_name ~= "" then
		local file_exists = vim.loop.fs_access(target_dir .. "/" .. new_file_name, "W")
		if not file_exists then
			vim.loop.fs_rename(target_dir .. "/" .. old_file_name, target_dir .. "/" .. new_file_name)
		else
			print("File '" .. new_file_name .. "' already exists! Skipping...")
		end
	end
end, { remap = true, buffer = true })

Fixes

Remove unnamed ghost buffers when using :Lexplore

This snippet fixes the issue of Netrw spawning empty buffers every time you call :Lexplore after you opened a file. With this snippet, use the function toggle_netrw instead of :Lexplore.

Credit for this code goes to david-lorenzo. Transcribed into Lua by me.

-- Remove all empty "No Name" buffers that are unmodified
local function clean_empty_bufs()
	for _, buf in pairs(vim.api.nvim_list_bufs()) do
        if
            vim.api.nvim_buf_get_name(buf) == ""
            and not vim.api.nvim_buf_get_option(buf, "modified")
            and vim.api.nvim_buf_is_loaded(buf)
        then
            vim.api.nvim_buf_delete(buf, {})
        end
	end
end

-- Clean up Netrw's empty buffer artifacts and let that logic toggle it
local function toggle_netrw()
	clean_empty_bufs()
	local flag = false
	for _, buf in pairs(vim.api.nvim_list_bufs()) do
        local e, v = pcall(function()
            return vim.api.nvim_buf_get_var(buf, "current_syntax")
        end)
        if
            (e and v == "netrwlist")
            and not vim.api.nvim_buf_get_option(buf, "modified")
            and vim.api.nvim_buf_is_loaded(buf)
        then
            flag = true
            vim.api.nvim_buf_delete(buf, {})
        end
	end

	if not flag then
		vim.cmd(":Lexplore")
	end
end
Check out david-lorenzo's vimscript version at:
https://github.com/david-lorenzo/.dotfiles/blob/main/.vim/explorer.vim

Fix files being created in the wrong directory when using :Lexplore

Using :Lexplore, files created with % are mostly not placed in the directory you expect. This is because Netrw does not properly “change” and “enter” into the directory it should for creating the file. To fix this issue, you can overwrite the file creation keybinding % with your own that properly sets the directory.
Doing this introduces a new issue, however, of the newly opened file being now shown inside your Netrw-drawer. To fix this undesirable behavior you can further add some commands to your keybinding that will: save the file, close the buffer and reopen Netrw.

Credit for this fix goes to u/LinearG on Reddit.

vim.keymap.set("n", "a", "Ccd%:w<CR>:bw<CR>:Lexplore<CR>", { remap = true, buffer = true })
remap <buffer> a Ccd%:w<CR>:bw<CR>:Lexplore<CR>

Prevent Netrw from taking over the clipboard

With the default settings, Netrw will try to keep the “clipboard’s values unchanged” which can sometimes lead unexpected issues of not being able to properly copy/paste. To fix this issue, simply turns Netrw’s clipboard feature off:

vim.g.netrw_clipboard = 0
let g:netrw_clipboard = 0

Fix subfolders “unloading” when refocusing vim

Warning

This bug is caused by using vim.g.netrw_liststyle = 3. You better avoid it by not using that option.

If you have subfolders expanded inside Netrw and somehow refocus vim (i.e. tabbing in and out), Netrw will “unload” your subfolders. They will now be displayed as empty text files that you cannot open, requiring you to re-open the parent-folder to make them appear as actual expandable folders again. As a band-aid solution you can use this fix.

vim.g.netrw_fastbrowse = 2
let g:betrw_fastbrowse = 2