Once you have used ‘notepad.exe’, you have used all text editors—they said. A text editor is a text editor is a text editor—they said. After the first few years of running Linux/Unix professionally, I kind of subconsciously agreed with this idea, eventhough I knew Vim—I thought I knew Vim. But when other people who actually knew how to use Vim used it, Vim still looked like magic.
If you have worked in a command line at some point, I am sure you can appreciate the wisdom of learning how to use a text editing program properly. On Unix/Linux command lines, text is king. Therefore, learning how to manipulate text effectively goes a long way for your productivity. If you know how to open a file and edit its content, that enables you to configure your system too.
The text editing program I prefer for these kind of work is Vim. It is also the text editor I can pretty much expect to find in any environment I log into—laptops and servers alike. Vim is available on multiple operating systems including Linux—which is my OS of choice.
Like many before me, I started my text editor journey by running
vim, promptly feeling lost, then failing to exit vim, and finally resigning to reboot the computer instead. Thus, I initially became an
emacs user—primarily because
nano was not well-known at that point. Eventually, I learned the bare minimum of vim use, just enough to do basic text editing.
What changed my mind about Vim was actually investing some time to learn it. Vim has a notorious learning curve. After years of already working on Linux, I only spent a decent amount of time to learn Vim and customize it to my liking somewhere around 2009. I can say without a doubt that I ended up liking Vim a lot—it definitely helped my productivity. It is powerful and versatile—and more importantly, did I mention I like it?
Back in the day, my vim setup was a jumble of config files and a bunch of plugins dropped into a directory until it croaked reasonably the way I wanted. It was done out of necessity because vim did not have decent package management for plugins at that point. Later when Pathogen came along, I jumped at the opportunity to organize vimfiles better. While Pathogen made it easier to organize vimfiles and manage plugins, it did not have a inbuilt way of tracking changes from multiple plugin sources over time.
At this point I was already using
git and I was familiar with the relatively new
git submodules feature. I felt git submodules could be used to manage individual plugins effectively. I looked around to see if anyone had already thought of that. Eventhough I am pretty sure others may have thought about it—to the best of my knowledge—no one had publicly shared a similar setup at the time. So I did it using submodules—which was a humble brag for me. These past versions of my vim configuration files are no longer there. An archived, somewhat-later version is there in a git repo though.
Since then, the most obvious change in how I maintain my vim set up had been the switch to
vim-plug for plugin management. The excellent vim-plug eliminated the need to juggle git submodules and made the whole process quite painless.
The sections below will describe the vim configuration I am using. I will try to keep this post reasonably updated in future as well, in the hope it might be useful to someone—just like it helped me to read what others were doing.
Few things to note:
- These should work with both regular
- When describing below, I have grouped some relevant sections together for convenience. They may be spread around in the actual
- Latest version of my vim configuration can be found in the
.vimrcof the git repo, not this post.
A Few Useful Vim Concepts
Before we begin, I would also like to quickly introduce you to a couple of key vim concepts I wish someone had explained to me much earlier.
Vim has multiple modes. Vim is what you call a ‘modal’ editor, which simply means vim has a few modes to work with.
As an analogy, think of a smartphone these days. There is a limited number of ways you can interact with it physically, but you have seemingly boundless amount of things you can do with it. For example, simple tap on the screen behaves differently based on which mode you are in. The singular touch input in this example can mean different interactions such as waking up the screen, unlocking, launching camera app, repositioning focal point, focusing on something, taking a photo, sharing a photo with someone, liking someone’s photo in another app, etc. Based on the context (or mode, if you will), the same physical thing you do, can give different results.
Vim is somewhat like that. There is an
Insert Mode where you can input text (i.g., typing) into the editor. There is a
Visual Mode where you can select a section of text so that you visually track which selection of text you are taking actions on (e.g., copy selected text). Then there is the
Normal Mode where you do everything else, such as moving around and manipulating text (e.g., cut, copy, paste, delete, etc.).
You can learn more about these modes and how you can enter/exit them, you can check the Vim Wikibook.
Editing with Vim is like programming your text. Which is a roundabout way of saying that Vim has shortcut keys/key sequences. You can ask Vim to do simple actions or combine multiple instructions to do more complex actions, which can be intuitive once you learn the basics.
Since you are limited to interacting with a software using inputs devices in your computer, there are bound to be limits to what you can input. Vim works around this by having shortcut keys or key sequences. Notice how I said key ‘sequences’ not ‘combinations’? Vim usually have shortcuts defined in such a way that you can press keys followed by other keys rather than press all of at once.
For example, pressing the letter
d within the
normal mode tells vim to ‘delete’ the next character. If you want to delete the next 5 character, the instruction becomes
dw deletes the next word, and
3dw deletes the next 3 words;
dd deletes the entire current line of text.
7dd deletes 7 lines starting with the current. You get the idea.
If we take this a little further, you can say things like “delete text up to the next occurrence of character
, by pressing
dt, in the
normal mode of course. These actions can be repeated by pressing
., again while in
normal mode. Want to change the text instead of deleting it? Replace the ‘d’ with a ‘c’ (e.g.,
ct,). Want to just select the text visually instead of both delete or change? Use ‘v’ instead of ‘d’ or ‘c’ (e.g.,
vt,). You can also throw directionality into the mix by using
h, j, k, l as arrow key alternatives.
The good thing is, you do not have to remember everything. You can build up the set of instructions with basic building blocks, entering one key press at a time. Sort of like conducting an orchestra, or like programming your text editing. Pretty neat, right?
You can define your own shortcuts. Vim allows you to define your own shortcuts in a couple of different ways, some of which you will see below.
The key is that Vim allows you to prefix your keyboard shortcut sequences with a special key (called
leader key), so that your own shortcuts will not conflict with inbuilt vim shortcuts.
Personally, I prefer to set shortcuts in what I think as “the vim way”. To explain it a bit further, I prefer to set shortcuts that do not break default vim features, at least logically adjacent to their inbuilt counterparts if there are any, and do not hamper muscle memory in the long run. You can see for yourself if the configuration below adhere to this within reason.
buffers are different editing spaces, whereas vim
tab pages are not. ‘Vim buffers’ are not to be confused with ‘vim tab pages’ or ‘vim windows’.
buffer in Vim is an editing space in memory. You can have a file already opened there, or you can save to a file later, or you can discard it. You can have multiple buffers open in a Vim instance.
window in Vim is a view into a buffer. You can have a single window with a single buffer, or you can have multiple views (e.g., as horizontal/vertical screen splits, as standalone windows) into the same buffer. For example, you can split your screen area into two windows and view two different locations of a file you have opened. Just remember, the “window” mentioned here is a vim window (i.e., usually visible as a full-screen or a split-screen area)—not necessarily a graphical window like you are used to.
tab page in Vim is a way to organized vim windows. Which means each tab page can have multiple vim windows (e.g., split windows). Therefore, you can have the same buffer viewed in more than one tab page too.
I know this can be confusing. You can see if the the following summary helps. Vim help summarizes this as:
bufferis the in-memory text of a file.
windowis a viewport on a buffer.
tab pageis a collection of windows.
Trying to use tab pages as different file editing spaces is a common mistake that can lead to confusing errors. If you are not sure about what to use, try
buffers first since they are the primitive you need as editing spaces and you view them anyway in ‘windows’. If you think you need ‘tab pages’, you can introduce them into your workflow later.
Vim is extensible with plugins. You can add features/functions not inbuilt by using plugins, which are programs written in
vimscript or other programming languages. You will see below which plugins I am using.
To summarize these key concepts:
- Vim has multiple modes
- Editing with Vim is like programming your text
- You can define your own shortcuts
buffersare different editing spaces, whereas vim
tab pagesare not
- Vim is extensible with plugins
Explaining My Configuration
These are built around the default vim installation environment found in the Fedora-family of Linux distributions (i.e., including Fedora*, CentOS, and Red Hat Enterprise Linux) because those are my usual work environments.
My .vimrc starts with some basic settings.
With the comments accompanying them, these should be pretty self-explanatory. Most of these so some basic convenience-oriented settings or improve visual cues.
I should however mention the
set autowrite. According to the vim documentation,
autowrite can save the file on certain actions, even if you had not explicitly asked to save (i.e., “write” in vim terminology).
I like to avoid surprises like this as much as possible. However,
autowrite is one of these very few exceptions I have left because it makes up in convenience. For example, it avoids the annoying ‘unsaved content warning’ when switching between buffers. If you are not sure about this, you should probably avoid setting (i.e., enabling) it.
Next up is something that actually has an effect on the text you will be editing—how the
tab character/key is handled.
I know how polarizing “Tabs vs Spaces” debate can be. Therefore, I will not get into it. I used to be in ‘tabs’ camp in the very beginning, but I switched to using spaces instead of tabs where I can, mainly for the purpose of getting a reasonably consistent visual experience across different environments.
I prefer to have 4 spaces per tab because most of the languages I work with these days (e.g., Rust) play nicely with that. The
bs settings help with backspace among other things when you use spaces instead of tabs. If you do not set these, using backspace to delete all the expanded tab characters would become tedious.
I also have set automatically enter spaces when I press the tab key with
set expandtab. This is another potential pitfall you should note. If you do not want to expand into spaces, then avoid setting expandtab.
Then there are some tools (e.g., Python and Go) which do not always handle spaces well when they expect tabs. For those you need to set exceptions. I have set a few exceptions for tab handling later in the configuration.
The comments here are pretty self explanatory. Something to remember is if you set
ignorecase, case sensitivity is ignores across everywhere patters are used. This can lead to tricky situations when you use pattern search and replace type of actions. Therefore, I have left it disabled.
Most of the settings here are on non-printable characters. Therefore, they do not have an effect on the text you are editing, only acts as visual cues while you are in the editor.
The exception here is
autoindent, which actually indents text automatically based on the indentation of the previous line. You can disable this by explicitly using
noautoindent (i.e., disable temporarily by entering
:set noautoindent in normal mode, or adding
set noautoindent to .vimrc).
You do not need to use a mouse with vim—in fact, it is discouraged. But if you want to do useful things like scrolling at your speed while doing a visual inspection, and then click to go to somewhere, you can. While I love using vim, I also am not militant about being keyboard-only. There are times when adding a mouse into the mix—or more accurately, not rendering the mouse/touchpad useless—can be helpful when working with vim. This is why I enable mouse too.
Vim also has a GUI version, usually called
gvim. It comes with an interface similar usual GUI programs, complete with things like toolbars, menubars, scrollbars, etc.
When I use gvim, I prefer to have a clean and simple windows, somewhat emulating what the terminal version looks like. If you prefer the GUI elements you can skip these settings.
Again, these settings a explained in the comments.
Finding the name used by your preferred font and setting it permanently can be a little tricky. One easy way to do that is to:
- First, in normal mode of
:set guifont=*and hit enter. It will open the font selection dialog of your environment. The font you set this way is only temporary (i.e., until you close vim).
- Once you make the preferred selection of font and size, in normal mode, give
:set guifontand hit enter. It will show the used name of the font. You can use the name later in your .vimrc to set the font permanently. Note that you could use the escape character
\before special characters such as spaces in the font name.
In the example above, I have added “Inconsolata-g” font in “Medium” typeface at the size “11” points. If you want to set any other monospace font like Fira Mono, Source Code Pro, DejaVu Mono, Hack, etc., you can do so with
guifont. If you use vim in a terminal instead of gvim, then the font is inherited through terminal settings.
Next comes a very important setting, eventhough it is just one line.
As explained earlier, Vim lets you define your own shortcuts without risking conflicts with defaults, using a value called a “leader”—referred in .vimrc as
<leader>. By default, the leader key is set to “
\”. Due to the ease of reach, I prefer to set the leader key to be “
,”. Therefore, when you see something like
<leader>y it translated to
,y in my setup.
Would this not conflict with inserting a comma?—you might wonder. There will be no conflict because you type in (i.e., insert) commas of your text in
insert mode while you invoke shortcuts in
Next is another interesting part—plugin management. Vim also has an inbuilt plugin manager since version 8. However, I have not looked enough into it. Since my current setup works really well, I did not have a need to change it either.
vim-plug developed by Junegunn Choi, as the plugin manager. It is written in vim script, thus do not need external runtimes or complex manual installation steps. With ‘vim-plug’ installing and keeping plugins up-to-date is a breeze.
Plugins are defined between the ‘vim-plug’ invocations of
call plug#begin() and
call plug#end(). I pass the parameter
call plug#begin() so that it know where to install my plugins. In this case, the parameter is a directory called
bundle inside the main vim files directory
~/.vim. I have it there because it is a leftover from the days when I used a different plugin manager.
I am not going to go one by one in this plugin list. However, as you can see above, I have grouped my plugins into a few areas such as:
- “Augment Vim behavior”
- “Augment UI elements”
- “Augment filetype handling and syntax highlighting”
- “Add utility”
- “Add colorschemes”
Since all of my plugins are added via GitHub, you can find out more by visiting the relevant repository pages. To get the URL of each plugin repository page, append the name in the plugin definition after “
https://github.com/”. For example, “easymotion/vim-easymotion” repository can be found at “https://github.com/easymotion/vim-easymotion”.
Some of the plugins here either need to be configured or can be configured. Some of the features enabled by these plugins, along with the shortcuts they introduce, are documented in the
README.md file of the git repo.
I am again not going to explain the above any further because they are pretty self-explanatory with the help of included comments.
If you look closely as the sections of the same
.vimrc file I have been explaining so far, you will notice it has a syntax. As I mentioned earlier, Vim has an inbuilt scripting language. You can use this language to write custom functions which can make things easier for you by scripting them.
In the above example, there is a function with the name of “
DiffWithSaved()” which combines inbuilt features of vim to find if there has been an changes since you last saved. If there are, it will present the differences between the last saved state and current state in a view similar to the Unix
diff. Finally, it can be invoked with a command named “
I have defined a few more functions as well. Please note that
ToggleFullScreen() function has an external dependency, an external program named
While these functions define what to do, they are not automatically invoked. The way I have chosen to call them is via either shortcut keys or function keys.
You can see that in the above,
QuickfixToggle() are configured to be invokes with
<leader>q respectively. As per my configuration, this translated into pressing
I have mapped some useful shortcuts to deal with cut/copy/paste with clipboard in
gvim. These complement the inbuilt
p for cut/copy/paste respectively, but for external clipboard (e.g., OS clipboard). I also have
,v) to select the text that was pasted into vim, right after it was pasted.
In addition to custom shortcut keys, I have also mapped some of the function keys (e.g., F1 - F12 keys in the keyboard) to do useful things.
You might notice that the convention I use is: function key mappings only change editor environment, whereas anything that affect the actual text are mapped as shortcuts with a “leader” prefix.
In the above, I have essentially remapped F1 key as another
ESC key to avoid potential accidental F1 key presses when reaching
ESC. F4 toggles spellchecking, F7 uses
junegunn/limelight.vim plugin, and F11 calls the above mentioned
ToggleFullScreen() function. The rest should be self-explanatory.
I also have a shortcut for when you edit a file away, but forgot you needed
sudo privileges to save it. Instead of pulling your hair out and starting from scratch, there are things you can do. The following makes one of those things even more convenient to use (i.e., instead of using
:w to save, type
:w!! to save with ‘sudo’ privileges).
I mentioned earlier that
buffers are the way to go when you need to keep multiple files open. The following section of the settings map a few shortcut keys to make switching between buffers faster.
In addition, I have also configured the plugin
buftabs here. It shows which files you have opened at the bottom of the vim window. You can not point and click it to switch between buffers, but rather provides a minimalist indication of opened buffers and statuses.
Finally, we have the exciting part—colorscheme! The first two lines
background set two values explicitly rather than try to derive them from the environment.
termguicolors setting explicitly says that the terminal you are using supports GUI colors. It does in my case because most of the time I use GNOME Terminal which comes with Fedora. If your terminal does not support GUI colors, then do not set this.
background setting is to make my terminal background dark. Like many people who need to stare at a screen for a long time, I too prefer dark themes whenever I have the option. Some colorschemes select between dark and light versions based on this value, which is why I have made ‘dark’ explicit. If you prefer light, you can set it to ‘light’ too.
If you do not need either of these two, then you should not set them because some colorschemes would look weird if you set the values different from what they are expecting or capable of handling.
With those out of the way, I finally set a colorscheme. My colorscheme of choice have changed overtime. These days, I prefer a theme called “One” which has both a light and dark version (picked based one the
The end result should look something like this (screenshot on Imgur).
That is about it for this post. Since it is already long, I did not try to include further details such as what the plugins do or which shortcuts they introduce. If you would like to hear about these details—or just wanted to give me your comments—please let me know via email or @s/DMs.
PS: I also re-posted this in dev.to where it gained a significant amount of interest (e.g., featured in the weekly “must-reads” list). Since this meant a lot more people read it there, the dev.to re-post is now another place where you can join the conversation. But this post remains the canonical source.