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.
There are other text editors I occasionally use such as "gedit" and "Apostrophe". But, most of the time, when I am typing something, writing code, or editing a configuration file, I am using vim.
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
vim
orneovim
. - When describing below, I have grouped some relevant sections together for convenience. They may be spread around in the actual
.vimrc
file. - Latest version of my vim configuration can be found in the
.vimrc
of 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 5d
. While 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.
Vim 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'.
A 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.
A 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.
A 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:
A
buffer
is the in-memory text of a file.
Awindow
is a viewport on a buffer.
Atab page
is 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
- Vim
buffers
are different editing spaces, whereas vimtab pages
are 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 smarttab
and 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
gvim
, give: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 guifont
and 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 normal mode
.
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.
I use 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 '~/.vim/bundle'
to 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.
One thing to note is the section where I have included tab behaviour exceptions (e.g., for Ruby and Go) as I mentioned earlier. Some other exceptions are handled automatically by file type plugins.
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 "DiffSaved
".
I have defined a few more functions as well. Please note that ToggleFullScreen()
function has an external dependency, an external program named wmctrl
.
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, DiffSaved
and QuickfixToggle()
are configured to be invokes with <leader>?
and <leader>q
respectively. As per my configuration, this translated into pressing ,?
and ,q
respectively.
I have mapped some useful shortcuts to deal with cut/copy/paste with clipboard in gvim
. These complement the inbuilt x
, y
, p
for cut/copy/paste respectively, but for external clipboard (e.g., OS clipboard). I also have <leader>v
(i.e., ,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 termguicolors
and background
set two values explicitly rather than try to derive them from the environment.
My 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.
My 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 background
setting).
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 leave a comment, or let me know via email or @s/DMs.
Originally posted at: https://gaveen.me/2020/02/my-vim-story/
My updated vimfiles can be found at:
Vimfiles
This is my current vimfiles. Plugins are managed with vim-plug
. These should work with vim/gvim and neovim.
This is not intended as a distribution, as I may change it depending on the work I'm doing. Plus, I pretty much only use this under Linux. But, you are more than welcome to use my vim files to explore. I have tried to keep my .vimrc
file well commended for your convenience.
How to use
If you still want to use these vimfiles, this is how you can do so.
First, you'll need to clone this repository.
$ git clone https://github.com/gaveen/vimfiles.git
Then, you could create symbolic links to the .vim
directory and .vimrc
file. Assuming the location where you cloned the repository is ~/Apps/vimfiles
, you can do something like:
$ ln -s ~/Apps/vimfiles/.vim ~/.vim
$ ln -s ~/Apps/vimfiles/.vimrc ~/.vimrc
Finally, launch vim and install the plugins. (Note:…
Top comments (14)
Bill Joy, the creator of
vi
, who used an ADM-3A terminal (which is why some of the keys are mapped the way they are, and the ADM-3A didn't have separate arrow keys, and placement of ESC and CTRL). His interviews where he is nostalgic about howvi
came about, in a world with 300 baud modems (2400 baud if you're lucky!), super-slow bandwidth where every character is "expensive" to transmit, whyvi
has so many short single-character commands. And how with modern computers with enormous speed and incredible bandwidth make the raison d'être forvi
to be obsolete.Nevertheless,
vi
persisted. (AndVim
too!)Nice one! My only words of caution are applicable if you find yourself editing files across a number of different systems (especially when there may be network security restrictions at play): The more heavily you rely on customization, the more you're going to bash your head on your keyboard trying to remember how to do it the vanilla way. I used to have a heavily modified .vimrc with all kinds of plugins and custom keybinds, but ended up getting rid of many of them in favor of building muscle memory around the built-in commands instead after sufficient time was spent bashing my own head on my keyboard. YMMV though :)
I agree, with caveats. Muscle-memory is a tricky thing. Therefore, learning the fundamentals is important before trying to customize. I probably should have mentioned that somewhere clear. Let me put it this way.
Whenever I introduce customization to an environments/tools—be it software or not—my idea is to learn the fundamentals of how it was meant to be used, then add bells and whistles. If you lose the bells and whistles, you still have access to the basics you learn to see you through. Same goes for vim.
If I can't get my customizations in, I should be able to get basic editing done without slowing me down too much. But if I can help it, there's no point of avoiding other niceties you can get. I have the ease of access with vimfiles on GitHub for the same reason.
nnoremap <Leader>/ :let @/=""<CR>
Might be a better way to clear / after the search. See stackoverflow.com/a/657484 (+ comments)
It can definitely be useful depending on what you want to achieve. However, I wouldn't necessarily call it "better" without a context.
To elaborate, while
:let @/=""<CR>
clears the search pattern, what I have (i.e.,:noh
/:nohlsearch
) only clears the highlighting (i.e., search pattern remains the same, just without highlighting), which is exactly what I want in most cases. This way, if I need to jump to the next occurrence of search pattern, I only need to pressn
which will do so, as well as start highlighting again.Sure, different workflow, different approach.
I guess I'm too used to my typical workflow: while I still need my search result - I want it highlighted, but after I'm done with it - it should be gone.
I use
:command! C let @/=""
so I can simply hit:C
to clearWell, mapping is one's personal preference of course :)
Vim is really amazing. Today I use vim only for changing some configuration on my system or a minor thing in a file, but I know I should use it more, much more.
Thanks for the awesome article (makes me excited in making vim my main editor)! :D
Thanks you for good article!
Hi, could you please explain what QuickfixToggle() is supposed to be used for?
Vim has an inbuilt QuickFix window feature which can pop into view on errors, etc, sort of like in popular IDEs. This is sometimes used by filetype plugins as well. For example, if you run a compile action while on a file, the compiler errors could be displayed in the QuickFix window. Here's an outside link which shows it with a little more detail.
While it can be quite useful, it can be annoying if you have to open it manually too often (e.g.,
:copen
or:cope
) or if you have to go close it by typing in the relevant command (e.g.,:cclose
or:ccl
).Therefore, I wanted to map a keyboard shortcut which would toggle the QuickFix window. This is the action I have defined in the
QuickfixToggle()
function. It is later mapped to<leader>q
.That's so cool! Thank you for a thorough explanation.
Thanks for sharing this helpful content, for me that i'm a newbie in Vim (with a lot of useless experience in VsCode and SublimeText) resulted very clearing. 👏🏽