This is not my beautiful home

It happened again. I’m not sure how I keep doing this all of a sudden, but a few times in the last month or so I’ve managed to create a file or folder called ~ in one project or another. Now the problem is that ~ is the shortcut for your home folder. In my case that’s /home/keith on Linux, or /Users/keith on MacOS. At that point things get really weird. You can’t see what’s in the folder or file because any command you use to try to look at it looks at your home folder instead. You can’t just rm -rf ~. No… please don’t even try that. I couldn’t even change the name with mv ~ foo because that would try to move my home folder into a new folder called foo which is probably somewhere in my home folder.

The trick is pretty simple, but since I already had to look it up a couple of times, I’ll post it here.

mv \~ foo

By escaping ~ with \~, the system knows that you’re talking about this file/folder in the current directory, not the shortcut to home. Now you have a foo folder there instead, which you can look inside of and see whats there, and delete it or whatever.

You could also delete it directly this way:

rm -rf \~

But that feel like playing with fire. Rename it first and make sure you’ve done the right thing.

Vim sessions

As you are working with Vim in a particular project, you’ll probably be opening more than just one file. Each file you open will be represented by a buffer. You might display these open buffers in various arrangements of splits within different tab pages. Or you might use one of many available methods to jump around between open buffers. After a few minutes working on a feature, you have all the files you need opened up and arranged just like you want them.

And then you need to do a quick task on another project, or maybe work on some other part of the same project. Or you need to reboot or you get carried away with your shortcuts and accidentally close Vim. Now you have to find all those files that you had open before, open them and arrange them back to how you had them.

That’s where sessions come in. Vim allows you to save the state of your Vim in a special session file, and reload it back in later, restoring the state that you were in.

The main command for this is mksession or, abbreviated, mks. You add a file path onto the end of that, and that’s where it saves your session. For example:

1
:mks ~/vimsessions/fixing_jira_2125

So you’re working on that Jira issue and something else comes up. You save your session. Close all your buffers or even open Vim in a new project, open up the files you need there, do what you need to do and wrap it up.

Now you’re ready to get back to that Jira issue you put aside. Restart vim with the command:

1
vim -S ~/vimsessions/fixing_jira_2125

And things are right back where you left off.

You can even restore a session without restarting Vim. You just need to source that session file. Right from within Vim, type:

1
:source ~/vimsessions/fixing_jira_2125

Note that restoring a session like this will NOT close any open buffers in your current session. So you might want to do that first.

Sourcing a session doesn’t restore everything in Vim to the way it was before, but it does restore a whole lot. Generally speaking, it restores your open buffers, splits, tabs, the current working directory, folds, global variables, options, and mappings. There are other things that can be saved. Check the help pages for mksession and sessionoptions by typing:

1
:help mksession

or

1
:help sessionoptions

To make sessions a little easier to work with, I made a few mappings:

1
2
3
nnoremap <Leader>ss :mksession! ~/.config/nvim/sessions/
nnoremap <Leader>os :source ~/.config/nvim/sessions/
nnoremap <Leader>rs :!rm ~/.config/nvim/sessions/

I made a directory called sessions inside of my neovim config folder (~/.config/nvim/). If you’re using regular Vim, you’d want to put that somewhere else. Just make sure the folder you specify actually exists before trying to save sessions into it.

The first mapping is for saving a session, ss. Note that it calls mksession! with an exclamation point at the end, which will overwrite an existing session file if it exists. It gives the path to sessions folder I created, but leaves the command line open for me to enter an actual file name. If you forget to put the file name, Vim will just let you know that. If you later open some more files and want to update the session, just call the mapping again. Now you should be able hit the tab key to autocomplete the session name you saved earlier. If there are multiple sessions, you should be able to tab through them until you get to the one you want. Or type the first couple of characters and then tab.

The second mapping, os is open session. It just sets you up to source one of the session files in the sessions directory. Same deal, enter a name or use tab-complete. Hit enter and you’re back where you were.

Finally, a bonus, rs is for remove session. Same deal, it just calls !rm for the system rm command. Type the name or autocomplete. Now you can clean up your old sessions.

These are just suggestions on how to use sessions. There are plugins that do all this and more with a fancier UIs, but I think this is pretty slick for three lines of code.

Removing whitespace in Vim

In my job, I work with JavaScript and React. We have a pretty strict eslint configuration that says a lot about what we can and can’t do with whitespace (among other things).

At first, I hated having my builds fail due to stylistic differences in opinion. Eventually I set up a linter in Vim itself so I know immediately if I’ve broken a rule, rather than waiting until the build fails. Also, with an ever-growing team, I see the value in keeping us all on the same page.

With the linter right in Vim, this next tip is not vital, but still pretty useful at times.

I wanted a way to automatically correct some of the common whitespace errors. Eslint does have a “fix” option, but I wasn’t totally comfortable with that. And the regex for fixing whitespace is pretty simple.

To remove trailing spaces at the end of a line:

1
%s/ \+$//eg

Just look for one or more spaces at the end of a line, and replace it with nothing. Ignore errors if it’s not found, and do it globally. /eg.

Multiple blank lines:

1
%s/\n\{3,\}/\r\r/eg

This one takes a bit of explanation. Our linter allows a single empty line, but not more than one. So I can’t just delete empty lines. Here, I’m looking for 3 or more newline characters. To search for a newline, use \n. Have to escape the brackets so it doesn’t search for those directly, so you get \n\{3,\} as the search term. (There are ways to setup search so it recognizes special characters like that, but for a simple one like this I didn’t bother.)

Then I want to replace that with exactly two returns. \r\r.

It seems really strange that we have to search for \n and replace with \r. But that’s how Vim rolls. When you’re searching, you look for newlines with \n. But when you’re inserting characters programatically, \n is NUL, not a newline. So you use a carriage return \r instead. I can’t guarantee that this will work in a native Windows file. But I don’t have to deal with such things currently.

Finally, our linter doesn’t like padding of code within a block. i.e.

1
2
3
4
5
6
7
8
function foo() {

notAcceptable();
}

function bar() {
acceptable();
}

This passes the single blank line test, but I need to enforce NO blank lines after an opening bracket.

1
%s/{\n\{2,\}/{\r/eg

Search for a bracket followed by two or more newlines. Replace with a bracket and a single carriage return.

So I got all these individual replacements working, but wanted to put them together in a single action. And make it possible to easily add more as needed. I decided to use a function.

1
2
3
4
5
6
function! KillWhiteSpace()
%s/ \+$//eg
%s/\n\{3,\}/\r\r/eg
%s/{\n\{2,\}/{\r/eg
endfunction
nnoremap <Leader>w :call KillWhiteSpace()<CR>

Now, two keystrokes cleans up any file nicely. And it’s clear what this is doing and easy to add more rules as needed.

Fixing netrw

Recently I wrote about a few file management solutions in Vim and I mentioned some problems with the netrw and vinegar-vim solutions. This was bugging me so I sat down and figured out what was going on and how to handle it. I should probably also mention that I use NeoVim. I can’t say 100% that this is also an issue with regular Vim, but I suspect it is.

The main issue was the fact that I had set hidden turned on in my Vim config. When you open a directory in netrw and hidden is set to true, things get into a weird state. netrw itself opens up in a read-only buffer, and that buffer doesn’t get closed when you navigate away from it or choose a file. It doesn’t even get closed if you try to delete the buffer with :bd. However, it does go away if you delete it by its number, :bd 1.

You should be able to see this behavior if you have set hidden on and do :edit ., choose a file and then :ls. You’ll see the netrw buffer in the list. Ideally you shouldn’t.

What I found out is that this behavior doesn’t occur if you open netrw by calling :Explore. But that just opens netrw in the directory of the currently displayed file. So that’s half the problem solved, but I also wanted to be able to open netrw in the current project directory, i.e. the directory where Vim was launched from.

Some digging around brought me to this:

1
2
3
nnoremap - :Explore<CR>
" nnoremap <Leader>f :Explore <C-r>=getcwd()<CR><CR>
nnoremap <Leader>f :Explore .<CR>

So we have the simple - mapping which just calls :Explore. Opens the dir of the current file. netrw behaves. Great.

The next one was trickier. You can pass a directory to :Explore, but how to get the current directory and pass it to the command? <C-r>=getcwd()<CR> gets the current working directory and inserts it in the command line. Just before that, I have :Explore with a space. Then I follow it up with a final carriage return.

Update

I was an idiot. Rather than the escape code and =getcwd() stuff, you can just :Explore .<CR>. Has the same effect. Not sure why I didn’t try that to begin with.

End Update

This opens up netrw without it getting into that weird state. Select it or close it and it goes away. For real. This makes me happy.

One more little bonus tip. If you don’t like that big banner on the top of netrw’s ui, just add the following to your config:

1
let g:netrw_banner = 0

You can always toggle it back on with a capital I if you need it.

Sadly, I don’t think this solution will really help if you are using vinegar-vim, because that plugin continues to call edit internally.

Build Systems in Vim: make

If you use a dedicated IDE designed for a specific language or platform, you probably have some built-in shortcuts for compiling, building, running your project. But if you’re using a more general-use editor such as Vim, or even Sublime Text, Atom, VS Code, etc., you’ll need to set that kind of thing up yourself. This article shares some ideas on how to do that within Vim.

As you know, in Vim, it’s super easy to set up pretty much any key combination to take pretty much any action. So creating a simple launcher is really easy. Say you have a JavaScript based project that has a package.json script called build. This does all the babel stuff or webpack stuff or whatever else you’re using to compile your project.

Remember that :! will allow you to run any system command from within Vim. So calling out to npm is really easy:

1
:!npm run build

It’s easy to set this up as a mapped shortcut. Just choose your favorite function (or other) key and say:

1
nnoremap <F5> :!npm run build<CR>

That will work beautifully. The problem is, you’re putting something very project-specific in your global Vim configuration. If that’s the only project you ever work on, or all your projects are set up the same way, maybe that works for you. But what if you have a Ruby project, or Python project, or C or Java or even another JavaScript project that doesn’t have an npm script named build? You could start setting up other function keys to build different types of projects, but that can get a bit crazy.

My ideal scenario would be to have F5 as the global key that can build any project. So we need to have F5 do something generic, and put something into the project that knows the specific steps to take to build that specific project.

One solution could be a shell script. Make a file called build.sh or something, that looks like this:

1
2
#! /bin/bash
npm run build

Then chmod +x it to make it executable. That’s assuming you’re using bash and that’s your path to bash. Adjust as needed. Then set up your build key:

1
nnoremap <F5> :!./build.sh<CR>

Now, for every project you want to be able to build with F5, you just create a build.sh script with the right commands to do the build, and make it executable. Maybe the other scripts will run gcc or javac or a gulp or grunt file. Or who knows what else. All told, this solution is not too bad.

But another, probably better way is to use the program, make. make is a program that is designed to run custom build scripts. It has built-in integration with Vim, so it’s really easy to launch from within your project.

make may be already installed on your system. Run make -v in the terminal to check. If not, you can install it quite easily with apt or homebrew or whatever package manager your system has. I guarantee it’s there.

Now you set up your launch key:

1
nnoremap <F5> :make<CR>

Note that Vim already knows about make internally, so you don’t have to say :!make. Just :make will do.

When you run make, it looks for a file called makefile in the current directory, and if so, executes the commands within it. Makefiles have a specific format and can allow for very complex, multi-part build scenarios. It was really designed for C programs where you might need to compile a bunch of different files into separate “.o” files and then link them together. Maybe even run a preprocessor on them, link other external libraries, etc. You can set up different targets for each phase of the build, and each target can have dependencies, which can kick off other targets, etc. You can read all about it here.

But we can start off pretty simple here. For our npm example, our makefile would have a single default target and look like this:

1
2
default:
npm run build

No need to make it executable or anything. And if you have a Java project it might look like:

1
2
default:
javac main.java

Or something like that. You get the idea. You can also set up other targets like so:

1
2
3
4
5
default:
npm run server

clean:
rm -rf build

You can pass a target name into make, so you can set up a clean key like so:

1
nnoremap <F6> :make clean<CR>

Another cool thing about Vim’s make integration is that it doesn’t even have to use make. Say you’re super old school and you love Apache Ant. In your Vim config, say:

1
set makeprg=ant

… or however you launch ant on your system. It’s been so long, I forget. Anyway, now running :make will instead launch ant and run your ant build file.

File Management: ranger

We’ve been talking for a while about file management in Vim. Let’s take some time to talk about file management outside of Vim. In particular, I want to introduce a program called ranger.

ranger is a console-based file manager. You launch it by simply typing ranger in the console and it takes over, filling the current screen or window, offering you a visual view of the file system from the location you launched it.

You can install ranger through apt on Debian/Ubuntu or homebrew on Mac, and I’m sure it’s easy to find in package managers for other *nix distros.

ranger is a paned file manager similar to one of the modes in Mac’s Finder. You are always focused on the center pane. Moving right takes you into folders, moving left brings you back up the tree. If you are focused on a file, it will try to show a preview of that file in the right pane.

If the file is text based, the preview is easy enough. Otherwise, it generally skips the preview. Though there are ways to display image previews, either with ascii image plugins or other terminal specific hacks and third party program integrations. I haven’t bothered.

One of the great things about ranger (if you’re a Vim user) is that it uses Vim key bindings for folder navigation. k and j move up and down through files in the current directory. l moves right to go into a subdirectory and h goes left to go up to the parent directory.

You can also use gg and G go to the top and bottom of the file list in the current directory or / to search within that list.

To move a file, highlight it and press dd, navigate to where you want it to go and press pp. Use yy to copy a file instead of moving it. Note however that dd does not actually delete the file until you do pp to paste it. If you simply want to delete a file, use dD instead.

So yeah, the shortcuts in general are more Vim-like than strictly Vim, and will take a little learning. However, a lot of them are two key combos, and when you press the first key, a menu will pop up showing you a listing of what you can type next.

Renaming a file is a bit non-intuitive. Press a. I guess you can think of it as “appending” to the file name.

The g key gives you a “go” menu, with shortcuts to take you to common places on your file system. Super useful. Eventually you’ll start learning the more common ones by heart. gh = “go home”, i.e. cd ~.

There’s also a visual mode for selecting multiple files and performing actions on them. Even though I’m just skimming over stuff here, this is going to be a long “tip”. ranger is just that powerful.

Beyond managing and previewing files, you eventually probably want to open them in some program for viewing, editing or what have you. Just hit enter on a selected file to do that. But how does ranger know what program to use to open that file? Interestingly, it does not just rely on system associations for this functionality. It has its own internal system known as “rifle” that determines a file’s type and what programs exist on the system that can handle that type. This is all configured through a rifle.conf file.

Now manually crafting your own rifle.conf would be tedious, but ranger comes with a default one. You’ll probably need to tweak it a bit depending on what system you are on, what programs you have installed, and which programs you want to open for different file types. But that default config is hidden away in an application directory you don’t really want to touch. To make a copy of it, run:

1
ranger --copy-config=rifle

This will copy the default rifle.conf to ~/.config/ranger/rifle.conf where you can safely edit it, back it up, and share it among your different machines.

The rifle.conf file works by identifying the file type and matching it with a program on the system. For various types of text files, here’s what it has:

1
2
3
4
5
# Define the "editor" for text files as first action
mime ^text, label editor = $EDITOR -- "$@"
mime ^text, label pager = "$PAGER" -- "$@"
!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = $EDITOR -- "$@"
!mime ^text, label pager, ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"

Here, if the mime type of the file shows that it is text, it will use the program defined in the environmental variable EDITOR, which you naturally have set to vim, right? It also uses the PAGER variable to preview files. To see what that is set to, type echo $PAGER. It’s probably less.

Then, if the mime type does not include text, it looks at the extension of the file. If it’s one of the common ones listed there (xml, json, csv, etc.), it will again use the configured editor or pager program.

Moving down to images:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#-------------------------------------------
# Image Viewing:
#-------------------------------------------
mime ^image/svg, has inkscape, X, flag f = inkscape -- "$@"
mime ^image/svg, has display, X, flag f = display -- "$@"

mime ^image, has pqiv, X, flag f = pqiv -- "$@"
mime ^image, has sxiv, X, flag f = sxiv -- "$@"
mime ^image, has feh, X, flag f = feh -- "$@"
mime ^image, has mirage, X, flag f = mirage -- "$@"
mime ^image, has ristretto, X, flag f = ristretto "$@"
mime ^image, has eog, X, flag f = eog -- "$@"
mime ^image, has eom, X, flag f = eom -- "$@"
mime ^image, has gimp, X, flag f = gimp -- "$@"
ext xcf, X, flag f = gimp -- "$@"

This one looks only at the mime type, and then runs through a bunch of programs that might be installed on your system. If that has xxx line returns true, it will execute the command at the end of that line and exit the flow.

On my Ubuntu system, I do have eog (eye of gnome) installed for image viewing, so that worked great. But on my Mac, none of these worked. In that case, when you try to open a file, it will prompt you for a program to open it with. To fix that, I had to add a new line to the rifle.conf:

1
mime ^image, has qlmanage,  X, flag f = qlmanage -p "$@"

qlmanage is the built-in Mac program otherwise known as “Quick Look”. A simple Google search gave me the command line needed to launch it. Now, no matter which system I’m on, the same config will give me the same behavior, which is a quick view of an image that can be closed by hitting escape. If I were more into editing images, I could swap them out to have them open in PhotoShop or Gimp, or whatever.

Have some new file type that is handled by a specific application? You can pretty easily see how to set up an association for that based on the file extension.

In summary, ranger is a super powerful program. It will take you a bit of time to learn it, but if you’re into working on the command line and prefer keyboard over mouse, you just might love it.

File Management in Vim: filebeagle

In my quest to find the perfect file manager plugin for Vim, I’ve used NerdTree, netrw and vim-vinegar. All of them offer great features and functionality when I needed them, but they also all had minor drawbacks that wound up getting in my way when I wasn’t using them. What I’ve come to at this point is yet another plugin called filebeagle. Install it through whatever plugin management system you happen to use. You’ll probably also want to remove or disable NERDTree or vim-vinegar if you have either of those currently installed.

filebeagle sets up two launch shortcuts: - works exactly like vim-vinegar, opening the filebeagle UI to the directory of the file in the current buffer, while <Leader>f opens it up in the local directory where Vim was launched.

Once launched, the UI you get is very similar to netrw or vim-vinegar. It takes over the current window and offers you a list of the current files in the directory it was opened in. You can navigate and search just like the other plugins we’ve looked at, and open files in the current window, or splits, or tabs or as previews, etc.

filebeagle’s UI is probably a bit more minimal than the others we’ve looked at. But that works for me. It also doesn’t have quite as many features. You can create a new file in the current directory with + (creates an actual file) or % (just creates a new buffer that you’ll have to save to create a file). But it doesn’t offer file deletion, moving, renaming, etc. If you need those features, you might want to go with one of the other solutions.

For me, this more minimal functionality is acceptable. However, I did figure out a way to add some basic delete and move/rename functionality. filebeagle offers a command: :ClipPathname. This copies the full path of the file your cursor is on into the + register. You can then open a command line and paste it back in to an rm or mv command. Or, use these mappings:

1
2
nnoremap bd :ClipPathname<CR>:!rm <C-r>+
nnoremap bm :ClipPathname<CR>:!mv <C-r>+ <C-r>+

I used bd and bm. Think “beagle delete” and “beagle move”. But feel free to use whatever you want. Both of these end with the command line open for you to confirm the delete by hitting enter, or change the name or path of the file in the case of mv.

Sadly, the filebeagle UI doesn’t instantly update after one of these actions, but you can refresh it by hitting R.

What I really like about filebeagle though is that unlike netrw and vinegar, when I choose a file or just close the UI (using the q key), filebeagle goes away completely. It doesn’t hang around in an uncloseable buffer to annoy me for the rest of the session.

To see all of filebeagle’s options, type :help filebeagle.

Dirvish

There’s one more file management plugin I wanted to mention. I’s called dirvish. This is pretty similar to filebeagle, but with a few more advanced features. In fact, it was originally forked from filebeagle, but eventually completely re-written, according to the author. I haven’t used it extensively, but it definitely does a lot more than filebeagle. It was a bit more than what I needed, but if you’re looking to do more advanced file management from within Vim, this could be a good fit for you.

Update

I figured a workaround for the issues I was having with netrw and vinegar-vim. You can find that in this article. With that workaround in place, I find that plain vanilla netrw works really well for me and that’s what I’m currently using.

File Management in Vim: netrw/vim-vinegar

As mentioned in the last article, the NERDTree plugin helped me tremendously to feel comfortable when I was first starting out in Vim. It was the first step in making Vim feel more like a “real” editor or IDE and not some ultra-minimal command line tool.

But as I got more used to using existing buffers and fuzzy file searching, NERDTree started becoming less and less useful and at some point started getting in my way as much as it was helping me. That’s not a dig on NERDTree at all. It was just time for me to adjust the tools I was using to my current skills and workflows.

The first things I tried were netrw and vim-vinegar. netrw is a plugin that is built right into Vim. and vim-vinegar is built on top of netrw. Also, NERDTree hijacks some of netrw’s functionality, so if you have NERDTree installed, you should at least temporarily disable or uninstall it if you want to test out the stuff I’m talking about here today.

netrw is a much more minimal file manager. You can open it by typing :edit . or simply :e.. Or make a mapping for that like <Leader>e or whatever. Because . is a directory, not a file, it opens in netrw to let you browse that location. Another useful shortcut to make is for :Explore or simply :E. This is a lot like NERDTreeFind in that it opens to the location of the file in the current buffer. You might want to map that to <Leader>E or whatever makes sense for you.

The first thing you’ll notice is that netrw opens as a full window, not a split like NERDTree. And when you choose a file, it goes away automatically. If you really like the idea of the IDE-like file explorer stuck to the side of your editor, you may just want to stick with NERDTree. But this more ephemeral file management tool was just what I was looking for.

Up at the top, there’s a big header showing a bunch of information about where you are, what’s being filtered and how things are sorted, and some helpful shortcuts. You can do :help netrw to find out about a whole lot more shortcuts.

Like NERDTree, you can traverse the file system, open files directly, or in splits or tabs, preview, etc. You can create or delete files or directories. Again, see the help on how to do all this. And also like NERDTree, you can search with / and do visual selection, etc.

If you like netrw, but want a bit more, check out vim-vinegar by Tim Pope, one of the kings (THE KING) of Vim plugins. It adds a bunch of neat enhancements on top of netrw. It gives you the shortcut of - to open directly to the location of a file. It hides that top banner (it’s still toggleable). It lets you type . or ! to copy a file name to the command line area for performing other operations on a file. And some other neat things. Definitely worth checking out.

While netrw was much more of a fit than NERDTree for me, I still found a few annoyances. The main one is that once you open netrw, it creates a buffer that you cannot easily close. This is a known bug and there are various workarounds for it, but none that worked particularly well for me. I always had that netrw buffer hanging around. And since my workflow is heavily focused on open buffers now, this was really annoying. Note, that this is a netrw issue, but because vim-vinegar is a direct enhancement of netrw, it inherits the same issue.

However, this may or may not be that annoying to you. Try netrw out. If it works for you, and you like it better than NERDTree, then great! If you wind up having the same issues I had, stay tuned for the next article, which discusses the solution I’ve arrived at so far.

Update

I figured a workaround for the issue described in the end of this article. You can find that in this article. With that workaround in place, I find that plain vanilla netrw works really well for me and that’s what I’m currently using.

File Management in Vim: NERDTree

A lot of non-Vim users think of Vim as this impossibly minimal, spartan editor. After all, that’s what you see when you open it by accident or out of necessity. But a while back I saw a couple of coworkers using some IDE that looked really cool and amazingly nerdy, zooming through editing tasks at the speed of light. When I learned they were using Vim, my eyes were opened and I began my journey.

One of the first things that helps make Vim into a more IDE-like experience is some kind of file tree / project view / whatever. Something to let you see and choose your files right from within the Vim. Pretty much every other editor or IDE has such a feature.

The plugin many new users start off with for this purpose is NERDTree. It’s the one I started with and it went a long way to making me feel more comfortable in Vim. If you haven’t tried it yet and you don’t have any other solution for this and this is causing you pain, I strongly suggest checking it out.

There are other options, and in fact (as I’ll explain later) I’m currently using one of those other options. But I’ll cover NERDTree in this article and look at some others in future articles.

Install NERDTree through whatever plugin manager or other system you use to install plugins. It doesn’t give you any shortcuts by default. You can toggle it on and off with :NERDTreeToggle, but that’s a bit much to type, so make a mapping like:

1
nnoremap <F2> :NERDTreeToggle<CR>

While you’re in there, make this one, too:

1
nnoremap <F3> :NERDTreeFind<CR>

Now, F2 will open NERDTree in the directory where you initially started Vim. F3 will open NERDTree and navigate to the location of file in the current buffer in Vim. Of course, use whatever shortcut keys you want.

Once you’re in there, you can navigate the file system for your project, expand folders, move, rename, create and delete files and folders, etc. Press ? to get a full help view with all the possible commands. And because this is all within Vim, you get neat built-in features like using / for searching, visual mode selection for multiple files, etc.

NERDTree is super powerful and if you are not fully comfortable with Vim yet, using NERDTree will very likely help you out a LOT.

However, after using Vim for a while, I started making a lot more use of open buffers and fuzzy searching with FZF and ripgrep. (I’ll talk about both of those in future articles.) As I began relying more on those tools, my need for a full blown file explorer like NERDTree has diminished. I’ve also noticed a few things about NERDTree that have begun to annoy me slightly. One example is if I toggle it open, but then decide to use FZF to search for a file instead, often the file I searched for opens in the NERDTree split. Then I have to do some fancy rearranging to get things back to how I want them. This is not NERDTree’s fault at all. But this, and other similar issues highlight the fact that NERDTree is probably a bit more than I need at this stage.

So I started looking for some more lightweight alternatives that will do what I need, but not get in the way so much. Articles on what I’ve found are upcoming.

Hidden characters in Vim

Here’s a feature that most code editors have: the ability to show “hidden” characters. This usually means spaces, tabs and return characters. With Vim, this is really easy. In fact, you can show spaces, non-breaking spaces, tabs, return characters, trailing spaces and more. And you can choose which character you want to use for each one of these things.

This is useful when you import or use someone else’s file or copy and paste some code. Maybe you use spaces and you want to check to make sure this new code you added isn’t using tabs. Another use case: the eslint setup I use at work does not allow you to add trailing spaces to the end of a line, so it’s nice to be able to quickly check for them visually - and have them look different than other spaces, so they really stand out.

To turn on the visibility of these normally hidden characters, type the following:

1
:set list

To turn them off, type:

1
:set nolist

Or to toggle them off and on, type:

1
:set list!

That last one makes a useful shortcut. I have it set up something like this in my Vim config:

1
nnoremap <Leader>l :set list!<CR>

Now, by default, this might not show anything at all. You’ll probably have to specify what characters you want to use for each hidden character you would like to see. This is done with the listchars setting. Here’s what I have:

1
set listchars=tab:→\ ,eol:↲,nbsp:␣,trail:✗,space:·

It’s a simple comma-delimited list with the name of the hidden character, a colon, and the character you want to show in its place.

I have characters for tab, end of line (return character), trailing spaces and regular spaces. Note that tab uses two characters. The first character is shown where the actual tab character is. The second character is repeated as many times as necessary to fill up the space that the tab takes up. I have →\ - the arrow, plus an escaped space - so it only shows the arrow, like this:

1
2
····Great!·This·line·starts·with·spaces!↲
→ Oh·no!·This·line·starts·with·a·tab!↲

You might want to use something like →-, which would fill the rest of the space with hyphens:

1
2
····Great!·This·line·starts·with·spaces!↲
→---Oh·no!·This·line·starts·with·a·tab!↲

To me, the empty space after the tab stands out better, but to each their own.

Also note that I have a nice for trailing spaces so it really stands out:

1
This·line·has·trailing·spaces!✗✗✗↲

You can use a wide range of characters, including lots of common unicode symbols. Type :digraphs to get some inspiration. Note, however, that you should only use single width characters and should not use : or , as those are used in the definition itself. Sadly, this means you probably can’t use 💩 for your tab characters.

See :help listchars for more information on other hidden characters you can display. Some of them might be useful for your workflow.