The Valuable Dev

Managing Local and Remote Filesystems with Vim and netrw

Let's go exploring in Vim with netrw

When I began to use Vim, everybody was using NERDTree. So I followed: to navigate through my filesystem, NERDTree would be the answer for many years to come.

Nowadays, I mostly use a fuzzy finder to find the files I want, but a file explorer can still be useful in some situations:

  1. When I look at a new codebase. It helps to have a general overview of the filesystem, to understand the structure of the project.
  2. When I need to create, update or delete files and directories.

The more I use Vim, the more I try to get rid of my plugins, to use Vim’s native functionalities as much as possible. It’s easier than keeping track of 39093209 plugins introducing breaking changes too often. That’s why my interest for netrw grew overtime.

What’s netrw? It’s the file explorer shipped with most Vim packages. It’s still a Vim plugin, but if you didn’t compile Vim yourself, it’s likely that you have it, too.

So we’ll dive in netrw in this article. More specifically, we’ll see:

  • Different ways to open netrw: in netrw’s window, in a new window, or in a “project drawer”.
  • How to browse through your files and directories.
  • How to change netrw’s display, and filter your filetree.
  • How to mark files and directories, and perform some actions on them.
  • How to manage files and directory: create, open, rename, and delete.
  • How to open files with external programs.
  • How to bookmark specific directories.
  • How to explore filetrees on remote servers from your local, comfy Vim.

I assume here that you’re somehow proficient with Vim. If you don’t understand what’s happening in this article, you can look at my series of articles to learn Vim. Also:

Learning to play vim
If you like my articles about Vim, I’m currently writing an ambitious book about The Best Editorā„¢ with many more tips!

Are you ready to look at a different way of browsing your precious files? Let’s go, then.

Basics

You can do many things with netrw, so let’s look first at the very basics. First, for netrw to work, you need to set these options as follows:

:set nocp
:filetype plugin on

If you use Neovim, the options above are already set correctly.

If you want to disable netrw and never speak about it again, you can set these two variables:

:let g:loaded_netrw       = 0
:let g:loaded_netrwPlugin = 0

Useful if you want to use another file explorer, like NERDtree or similar.

Also, if you want to read the help for a specific keystroke inside a netrw buffer, you can run :help netrw-<keystroke>. For example: :help netrw-%. It also works for Ex commands; for example, :help netrw-:Sexplore

I encourage you to read the help if some keystrokes don’t work as intended. One of netrw’s big strength is its flexibility: you can customize it as you see fit, most of the time.

Vim help
:help netrw

Opening netrw

Let’s first see how we can open our file explorer.

Opening In the Current Window

To open Vim directly in a netrw buffer, simply give a directory path as argument when you run vim in your terminal. For example:

vim /my/dir/

The last slash / is not mandatory for opening local directories, but it is for remote ones. It’s also mandatory when you try to fetch a URL. To avoid confusion, I always add it.

Inside Vim, you can also use the :edit command followed by a directory name. For example, to open the directory of the file open in your current buffer, you can run:

:e .

The netrw buffer would then open in the current window, like any other buffer.

You can also use the command :Explore <dir> to open the directory <dir> in the current window. If you don’t give a <dir>, you’ll open the current file’s directory. This command would also open a split window if these two conditions are met:

  1. If the option “hidden” is not set.
  2. If you modified the current buffer, but you didn’t save it.

Opening In a Split Window

If you don’t want to open a netrw buffer in your current window, you can also summon it in a split window:

CommandDescription
:<size>Sexplore <dir>Create a horizontal split window above the current window, of size <size>, and open the <dir> in a netrw buffer.
:<size>Hexplore <dir>Create a horizontal split window below the current window, of size <size>, and open the <dir> in a netrw buffer.
:<size>Vexplore <dir>Create a vertical split window on the left of the current window, of size <size>, and open the <dir> in a netrw buffer.
:<size>Vexplore! <dir>Create a vertical split window on the right of the current window, of size <size>, and open the <dir> in a netrw buffer.
:Texplore <dir>Open a window and a netrw buffer (browsing <dir>) in a new tab.

If you don’t give any directory <dir> for the commands above, netrw will open the current file’s directory.

As you can see, you can specify the size of the window you want to open. For example, :20Vex will open netrw in a new window on the right, with a size of 20. If you don’t specify anything, the window will take half the current window. It’s exactly the same behavior as regular Vim splits.

If you want to open your netrw windows with a fixed size, you can set the global option g:netrw_winsize. For example:

let g:netrw_winsize=20

Additionally, after opening a new file buffer using netrw, you can switch back and forth between netrw and the file buffer with the command :Rexplore.

Finally, if you want to open Vim’s current working directory (the one displayed when you run :pwd), you can use a simple user command:

command! Oexplore exe 'Explore' getcwd()

If you want to know more about Vim user commands, I covered that in one of my article ;to learn Vim from the ground up.

Vim help
:help netrw-explore

Opening a Project Drawer

Window splitting in Vim is a great feature. It’s useful to copy and paste from one buffer to another, comparing two files, or… opening netrw.

But when you compare the behavior of netrw to other “project drawer” from other editors, it might seem odd that the file selected opens in the file explorer’s window. In most editors, this “project drawer” is a special, independent, and smaller window, often opened on the left side. Any file you’d open in there would then pop up in a new window, or in a new tab.

The following commands try to replicate this behavior:

CommandDescription
:<size>Lexplore <dir>Toggle a vertical netrw window of size <size>. Add a bang ! to open it on the right end side.

This command has some peculiar qualities:

  • The window takes the full height of Vim, even if you have other horizontal split windows open.
  • When you try to open a file, a buffer will be created in the window you called netrw from, not in the window where the netrw’s buffer is.

In short, it behaves more like these “project drawers” I’ve mentioned above. But even if it looks tempting to replicate what you might already know from other editor, I would recommend you not to use this command.

Vim has a specific window splitting system. The new window opened by :Lexplore is different, and make things a bit more confusing. For example, if you have already multiple split windows, in what window should the file you’ve selected be displayed? The one you come from? What was it? Or should it be the closest one to the netrw window?

Additionally, by trying to make this window special, it introduces some weird bugs, at least On My Machineā„¢. For example, when moving from the netrw window to another window with another buffer, the netrw buffer would suddenly open there too, inexplicably.

Another nasty side effect: after running :Lexplore, any file you’ll then try to open with netrw, whether you used :Lexplore or not, will always open in the last window you came from, not in the netrw window. Internally, :Lexplore set the global option g:netrw_chgwin to the window you come from, silently.

The mighty Drew Neil speaks about all of these inconveniences and more in one of his article, Oil and Vinegar - split window and the project drawer.

If you really want to open your file in another window, you can use one of the following keystroke instead of relying on :Lexplore:

KeystrokeDescription
POpen the file under the cursor in the previously accessed window.
<count>COpen the file in the window with ID <count>. Open in the current window if no <count> specified.

You can also run a couple of Ex commands:

Ex commandDescription
:NetrwCSet g:netrw_chgwin to the current window.
:NetrwC win#<number>Set g:netrw_chgwin to the window number <number>.

The easiest way to open your file in the window you come from is to use P. You can also use 2C if you have only two window open, and you’ve opened netrw’s window last.

Finally, to reset the global variable g:netrw_chgwin, you can run let g:netrw_chgwin=-1.

Vim help
  • :help netrw-P
  • :help netrw-C

Let’s see now how we can effectively browse in our filesystem with netrw.

Basics

Here are the basic keystrokes we can use to browse our filesystem:

KeystrokeDescription
ENTEROpen a buffer with the file (or directory) under the cursor in netrw’s window.
oOpen the file (or directory) under the cursor in a new horizontally split window.
vOpen the file (or directory) under the cursor in a new vertically split window.
tOpen the file (or directory) under the cursor in a new tab.
-Go up one directory level.
POpen the file in the previously focused window.
pOpen the file in the preview window.

Managing the Display

Here are some useful NORMAL mode keystrokes to manage the display of your files and directories. You can make some of them global by setting the corresponding global variable.

KeystrokeDescriptionGlobal variableExample
CTRL-lRefresh the directory listing.
iCycle through different listing display styles: “thin”, “long”, “wide”, and “tree”.g:netrw_liststylelet g:netrw_liststyle=0 (0 for “thin”, 1 for “long”, 2 for “wide”, 3 for “tree”).
IToggle the banner on top.g:netrw_bannerlet g:netrw_banner=0
sSwitch sorting between name, time, and size.
rSort in reverse order.
qfDisplay file’s size and timestamp of last modification.

Filtering the Display

What about keeping only what we need in our netrw window?

KeystrokeDescription
ghToggle showing or hiding dotfiles.
aCycle through three hiding modes determined by a regex.

If you want something more elaborate than gh, the keystroke a is here for you. It can hide or show files and directories using a regex; this regex is the value of the global variable g:netrw_list_hide.

Hitting a will cycle through three different display:

  1. Display everything.
  2. Hide the files matching the regex.
  3. Show only the files matching the regex.

For example, to hide all JPG and PDF images, you can run:

:let g:netrw_list_hide="\.pdf$,\.jpg$"

It’s also possible to hide every file specified in the .gitignore file, by adding the return of the function netrw_gitignore#Hide() to the hide list.

For example, to hide all PDF files, MD files, and files specified in .gitignore:

:let g:netrw_list_hide="\.pdf$,\.jpg$,".netrw_gitignore#Hide()

Last important thing: all marked files are considered part of the hide list. We’ll speak about marked files just below in this article.

Listing the Browsing History

The browsing history is updated when you… browse in a netrw buffer. What a surprise!

You can move through the history of directories visited using these keystrokes:

KeystrokeDescription
uGo to the preview directory.
UGo to the next directory.

You can control the count of history’s entries by setting the global variable g:netrw_dirhistmax. The default is 10.

By default, netrw will write its history in the file .netrwhist, in the first directory of the “runtimepath”. If you want to change this directory, you can set a value to the variable g:netrw_home.

Marking Files And Directories

We saw that marked files are automatically part of the hide list when hitting the keystroke a in a netrw window. But what are these marked files?

They’re simply files you’ve marked using specific marking keystrokes. Many netrw keystrokes and commands will act on the files marked.

These marked files end up in two different lists:

  1. In a global marked file list. There’s only one marked file list available.
  2. In a local buffer marked file list. Each directory has one, so each directory has its own list of marked files.

So, how to mark (or un-mark) files? Here are some keystrokes to do so manually:

KeystrokeDescription
mfToggle the marking of the file or directory under the cursor.
mFUn-mark all the marked files in the current directory.
muUn-mark all the marked files in every directory.
mrOpen a prompt inviting you to enter a regex, and mark all the files matching it.

You can also use the following command:

CommandDescription
:MF <pattern>Mark a list of files depending on the pattern <pattern>.

Notice that these regexes accept shell-style globs.

You can also mark the files which are already in another Vim list:

KeystrokeDescription
qLMark all the files part of the location list.
qFMark all the files part of the quickfix list.
mAMark all the files part of the argument list.
maMove marked files to the argument list.
cbMove marked files to the buffer list.
cBMark all the files part of the buffer list.

Weirdly enough, there’s no keystroke available to display the list of all marked files. But you can run the following command to do so:

:echo netrw#Expose("netrwmarkfilelist")

Even better: you can create a user command you can then map to a keystroke, if you want to. If you wonder what’s a user command, I’ve covered that in this article.

Finally, here are some interesting keystrokes to act directly on the marked files:

KeystrokeDescription
mvPrompt the user to enter a Vimscript command operating on all marked files, one at a time. Use % as filename placeholder.
mxPrompt the user to enter a shell command operating on all marked files, one at a time. Use % as filename placeholder.
mXApply a shell command on every file at once.
mzCompress (or uncompress) marked files.
mgApply Vimgrep to the marked files.
msSource all marked files.

We’ll see many more ways to operate on marked files below.

Managing Files and Directories

We have now multiple options to open and display our files and directories using netrw. Next, let’s see how to manage our filetree by adding or deleting elements.

Creating and Deleting

Here are the keystrokes you can use in a netrw window to add or delete files or directories. Under the hood, netrw will run specific shell commands to operate on the files of your liking; you can change these commands by setting a value to the corresponding global variables below.

KeystrokeDescriptionGlobal variable
dCreate a directory.g:netrw_localmkdir
%Create a new file (when the buffer created is saved).
DDelete the file (or empty directory) under the cursor.g:netrw_rm_cmd (for files) and g:netrw_localrmdir (for directories).

By default, you won’t be able to remove non-empty directory. You can however decide to always delete directories recursively, by running:

let g:netrw_localrmdir='rm -r'

The keystroke D will also delete all marked files.

Renaming Files or Directory

What about renaming what we already have?

KeystrokeDescriptionGlobal variable
RRename (or move) files and directories. It’s also possible to modify its path to move it.g:netrw_rename_cmd

This keystroke will also try to rename all marked files.

There is no problem to use this keystroke locally, but there’s a big caveat when used on remote files. In that case, it will copy the file first, and then delete it. The two operations are independent; if the copy fail and the delete succeed, you’ll lose the file.

We’ll see the remote possibilities of netrw below.

Copying Files

Copying files or directories require three steps:

  1. Select the target directory (where the files need to be copied) with the keystroke mt. If the banner is visible, the target path will be displayed there.
  2. Mark the files you want to copy with mf.
  3. Hit mc to effectively copy the files.

By default, netrw use the command cp under the hood. If it doesn’t work, a message will point out what variable you need to set to use a different the command.

Moving Files

In netrw, moving files or copying them is a similar operation.

Again, a word of caution: if you move remote files, they’ll be first copied and then deleted. You’ll lose your files if the copy operation fails and the delete operation succeed.

Here are the three steps to move our files:

  1. Select the target directory (where the files need to be copied) with the keystroke mt. If the banner is visible, the target path will be displayed there.
  2. Mark the files you want to copy with mf.
  3. Hit mm to move the files.

By default, netrw use the command cp under the hood. If it doesn’t work, a message will point out what variable you need to set to change this command.

File Permissions

Using netrw, you can also change the file permissions using the keystroke gp. It uses the CLI “chmod” under the hood; if you want to change it, you need to give a value to the variable g:netrw_chgperm.

Opening Files with External Applications

If you want to open a specific file using an external application, here are some keystrokes to do so:

KeystrokeDescription
xOpen the file under the cursor with the user’s preferred application.
XPrompt for arguments, then use your shell to call the executable file under the cursor with the arguments.
gxCan be used in any type of buffer (netrw and file buffers) to open the file (or URL) under the cursor with the user’s preferred application.

The keystroke gx is handy to open a URL from your buffer while editing. I use it all the time!

By default, netrw uses an application which can open user’s preferred applications, like xdg-open for example. You can change it by setting a value to g:netrw_browsex_viewer. For example:

:let g:netrw_browsex_viewer="xdg-open"`

If you set the value of this global variable to - (let g:netrw_browsex_viewer='-'), then netrw will try to run a function depending on the extension of the file. For example, if you try to open an HTML file, the function NFH_html() will be invoked, with the filepath as argument. You can then write some code in the body of the function to specify how to open the file.

You can find many examples in this file: $VIMRUNTIME/autoload/netrwFileHandlers.vim. If you don’t know where your Vim runtime is (or what’s the Vim runtimepath), you can look at this article.

Additionally, you can set different global variables to customize this functionality:

VariableDescription
g:netrw_gxControl how gx picks up the text under the cursor. The default is <cfile>.
g:netrw_nogxDisable the gx keystroke for non-netrw buffers.
g:netrw_suppress_gx_mesgDisplay messages from the browser open in Vim. Default is 0 (disabled).

Bookmarking Files and Directories

We also have the possibility to bookmark our favorite directories in netrw. Here are the most useful keystrokes to do so:

KeystrokeDescriptionMarked files?
mbBookmark the currently browsed directory.Bookmark all the marked files.
mBDelete the last bookmark.Delete all the marked files from the bookmarks.
qbList all bookmarks
<count>gbGo back to the bookmark number <count>.

All the bookmarks are written in the file .netrwbook. This file is located by default in the first directory of the runtimepath. Similarly to the history, you can also set the variable g:netrw_home to change the directory of .netrwbook.

You can also use the following Ex commands to manage your bookmarks:

Ex commandIn netrw bufferNot in netrw buffer
:NetrwMBBookmark file or directory under the cursor.Bookmark the current file open in the buffer.
:NetrwMB <files_or_dirs>Bookmark files and directories <files_or_dirs>

If you run :NetrwMB with marked files, they’ll also be all bookmarked.

Remote Operations and Protocols

We’ve seen in details how to manage our files and directories using netrw on a local computer. We can also use it to explore and manage the file systems on remote computers, via SCP or FTP!

There are two categories of operations we can do on these remote files and directories:

  1. Read and write.
  2. Only read.

Keep in mind that writing on a remote system is potentially destructive.

Under the hood, netrw use the file netrw.vim in $VIMRUNTIME/autoload/netrw.vim. It uses autocommands to intercept read and write for URL-like filenames.

This file netrw.vim is mainly a wrapper sending commands to external program, like ftp or scp. You can also read using other protocols (like HTTP), but writing and browsing a remote filesystem is always done via FTP or SCP.

Our netrw will read and write from temporary files copied from the remote system on the local computer. For Unix-like system (including Linux), these files will end up in the /tmp directory.

We can use all the commands we’ve seen until now on remote files, too. There are two important differences, however:

  1. As I mentioned already, if you want to move remote files or directories, you’ll need to do a copy first and then a delete. If the copy fails and the delete succeed, the file or directory will be deleted from the system. Copying manually the file first, and then deleting the files in a second step is safer.
  2. If you want to overwrite the command used by the keystroke d (to create a directory), you need to assign a value to g:netrw_mkdir_cmd, not g:netrw_localmkdir. The same logic apply for other operations; for example, to remove a directory: g:netrw_rmdir_cmd for a remote system, g:netrw_localrmdir for a local one.

To open a remote directory, you can use the following command:

vim <protocol>://<user>@<hostname>/<path>/

As we said earlier, the <protocol> can be “scp”, “ftp”, “http”…

As often, depending on the protocol you’re using, netrw will internally call a shell command to access the directory.

Vim help
:help netrw-protocol

Using SCP

What’s SCP? It’s a protocol to exchange files between clients and servers using SSH. As a result, the exchanges are authenticated and encrypted.

Using the pattern we’ve seen just above, if I want to open my home directory on my remote server from my local computer, I can simply run the following:

vim scp://hypnos@185.193.160.40/

A netrw window will then open, browsing the home directory of the user hypnos on my server with IP 185.183.160.40. Even better: if you use OpenSSH, you can write this kind of configuration in your $HOME/.ssh/config file:

Host server
     HostName 185.193.160.40
     User hypnos

If you don’t want to enter your password 3892 times while browsing, you can log to your remote server using one of your local SSH key. If you’re on a *nix machine, look at man ssh-copy-id for more details.

We can also directly open a file with, for example, the command vim scp://server/myfile.

Speaking of files, we can also use the usual Ex commands inside Vim to edit, read or write them. For example:

ExampleDescription
:e scp://user@ip/myfileEdit the file myfile in the current window.
:r scp://user@ip/myfileInsert the content of myfile in the current buffer.
:w scp://user@ip/myfileWrite the content of the current buffer into myfile. Useful to copy a file from your local to your remote server!
Vim help
  • :help netrw-externapp
  • :help netrw-transparent
  • :help netrw-ex
  • :netrw-ssh-hack

Using FTP

You can also open files using the FTP protocol. Since this protocol is not secure at all (a third party can intercept the data, including username and password), I’d recommend you to use the SFTP protocol (for SSH FTP) instead.

On the surface it works similarly than the SCP protocol. Just call a URL like vim sftp://user@ip/myfile for example, and you’re good to go.

There are two potential drawbacks, however:

  • It’s significantly slower than SCP.
  • Some FTP implementations are noisy and add some junk to the filenames. You’ll need to write a function NetReadFixup to clean them up automatically.

The benefit? You can do many more operations on files using SFTP compared to SCP.

You can also write a .netrc file (probably located in your home directory) to specify your favorite way to connect to a remote via FTP.

Obtaining a File

While browsing, you can use the O keystroke to fetch the remote file under the cursor. Vim won’t open it in a new buffer. If some files are marked, they’ll all be fetched.

These files are copied to the Vim’s working directory. To display the path of this working directory, you can run :pwd.

Reading via HTTP

Using netrw, we can also fetch some content from HTTP. For example, try to run the following in Vim:

:e http://www.google.com/`

Congratulation! You’re reading Google’s HTML.

If you try to write the file, netrw will try to upload it back to the remote URL. On my machine, it runs the command curl -T http://www.google.com, but it might be different on yours.

You can also use :r <URL>/ to insert in the current buffer, instead of opening a new one

Customizing netrw’s Mapping

The easiest way to customize netrw keystrokes is to declare your new mapping in the folder ftplugin. Again, if you wonder what it is, I’ve written about the Vim’s runtimepath here.

For example, if you want to toggle the netrw banner by hitting B instead of I, you can add the following to the file $HOME/.vim/ftplugin/netrw.vim (or $XDG_CONFIG_HOME/nvim/ftplugin/netrw.vim for Neovim):

map <buffer> <silent> B I

It works because all netrw buffers have the filetype “netrw”.

Master of Browsing

There are many other ways to customize netrw, but I think I’ve covered enough here to answer most needs.

What did we see in this article?

  • We can open the help for specific netrw <keystroke> by running the Ex command :help netrw-<keystroke>. It also works for Ex commands.
  • There is a command to open Netrw wherever you want, depending of the current window: on the side or on top of it.
  • You can go back and forth in netrw’s browsing history using u and U.
  • It’s possible to mark files and directories. The usual keystrokes will then act on these files.
  • Using netrw, we can create, delete, rename, or move files and directories.
  • It’s also possible to open files using external applications or commands.
  • Bookmarking directories can be a good way to open quickly whatever you need.
  • One of the most powerful feature of netrw allows us to open remote filesystems using SCP or FTP.

The native plugin netrw might not be the most stable or the most complete file manager out there, but, to me, it’s enough for the daily operations we all do on our precious files.

Vim help
:help netrw-quickmap
Share Your Knowledge