Bang! Vim!

Install (Neo)Vim

I’m not going to lie, Vim is a large mountain to climb. You could spend years learning Vim and still not know everything there is to know about it. However, getting to a point where you can be productive with Vim is not hard at all. You won’t be a master after this chapter, but you should be able to get normal coding work done.

This Vim tutorial is going to be different than most. I’m going to show you what you need to know to be productive with Vim. In other words, I will cover Vim topics in an order that will get you to a point where you can actually use Vim as your editor all day. Most Vim documentation covers each topic, in depth, individually. That knowledge isn’t tied together into a full workflow. You end up having to figure that out yourself. My goal with this chapter is to get you to a comfortable level with Vim so that you can use it to get actual work done. From there you can expand out as far as you like with the wealth of information on the internet and in books.

Before we go any further we need to get Vim installed. You notice I named this section (Neo)Vim. Vim is the standard, of course, but Neovim is a fork of Vim that aims to maintain backwards compatibility with Vim and reduce the code size. It has been around for quite a while now and is very stable. I personally use Neovim and have not had any issues with it. All of the plugins mentioned in this book work without modification in Neovim.

You can install either Vim or Neovim, both will work with all of the configuration settings and examples that will be covered in this book. One big improvement that Neovim adds is its built in terminal buffer. Both Vim and Neovim allow you to run terminal commands from within the editor, but only Neovim has a full-blown terminal mode. I cover the Neovim terminal later in this chapter.

Ubuntu Vim

Installing Vim on Ubuntu is just as straightforward as you would expect. Make sure you update the apt sources first so you get the most recent version of vim available.

$ sudo apt update
  $ sudo apt install vim

Ubuntu Neovim

To install Neovim on Ubuntu is a tiny bit harder. Neovim is installed with a PPA, Personal Package Archive. You can still install Neovim with apt, but you have to first tell apt about the Neovim package. You can also find more detailed instructions at the Installing Neovim page.

$ sudo add-apt-repository ppa:neovim-ppa/stable
  $ sudo apt update
  $ sudo apt install neovim

macOS Vim

Use Homebrew to install Vim on macOS. Make sure to update Homebrew sources before installing Vim to make sure you get the latest version. Be aware, this is not MacVim, which layers a windows GUI over Vim. We are sticking to plain ol’ terminal based Vim.

$ brew update
  $ brew install vim

macOS Neovim

Use Homebrew to install Neovim on macOS. Neovim has regular releases, so you should make sure to update the Homebrew sources before installing Neovim.

$ brew update
  $ brew install neovim

Vim Basics

I’m going to suggest that you start using Vim now. The configuration changes we are going to do in this chapter can be done easily in Vim. It will give you a chance to start getting used to the editor and show you that Vim isn’t as scary as you might think.

In order to do that you will need to know some very basic editing operations and commands. At this point you will have either Vim or Neovim installed. The program names are different for the two editors. The command to start Vim is simply vim. The command to start Neovim is nvim. Later on, in the configuration section, we will add an alias for Neovim so it can be started with just vim as well, but for now just substitute nvim where needed in the commands below.

Starting Vim

Starting Vim is as easy as just typing vim at the command line.

$ vim

When you do that you should see the Vim editor in your terminal.

The Vim User Interface
The Vim User Interface

It shows a title screen with the version of Vim, the author’s name, and some commands to get help. You will also notice a line of tilde (~) characters starting each line. This is a marker that marks the end of the buffer. If you are editing a larger file you can scroll past the end of the buffer to center the text on the screen. The tilde characters let you know where the buffer contents actually end. Since you don’t actually have a file open right now all you can see are tilde characters.

The very bottom of the editor is a status line. It gives information about how much of the buffer is visible, which line and column the cursor is on and other information. Below the status line is the command line. Many, but not all, Vim operations are entered on the command line. This will become clearer as you proceede.

Vim Modes

Vim doesn’t work like other text editors. Vim has what are called Modes. You can only be in one Vim Mode at a time and the keys you type perform different actions depending on the Mode you are in.

When you start Vim you are in Normal Mode. Normal Mode allows you to use your keyboard to move around in a file, find a specific piece of text on a line, delete characters, words or lines of text and so on. It is where you will spend most of your time in Vim.

Normal Mode also has a number of different commands the will activate the other Vim Modes. For instance, pressing the i character while in Normal Mode will make Vim change to Insert Mode. While in Insert Mode the keys of your keyboard act like you would expect in a text editor. Anything you type becomes content in the buffer. To exit Insert Mode and return to Normal Mode you press the <Esc> key.

Another mode you will use quite often is Command Mode. Pressing the colon key (:) while in Normal Mode will activate Command Mode and the cursor will be placed at the bottom of the screen in the command line mentioned above. Command Mode allows you to enter Ex commands. Vim was born from Vi, which is where the modal editing paradigm comes from. Vi was born from another editor named ex which is why Ex commands are available. You can do some file editing with Ex commands, but mostly they are used to perform supplemental tasks, like opening and saving files, searching for text and so on.

Quitting Vim

You may have heard the Vim joke; “I’ve been using Vim for about two years now, mostly because I can’t figure out how to exit it.”. This joke must have been taken to heart by the developers because there are instructions for exiting Vim displayed right when you start it now. It isn’t hard to exit Vim, once you know how, but it if you don’t know how it isn’t exactly obvious how to go about gaining the information. Let’s put the whole issue to rest right here. To exit Vim you use the :quit Ex command. If you don’t already have Vim running start it. You should see the start screen as shown above. Hit the <Esc> key to make sure you are in Normal Mode, then press the : key.

Vim Command Line
Vim Command Line

You should notice that the Vim command line has been activated and the cursor is placed there ready to enter a command. Type quit, then press <Return>. Vim will quit and you will be returned to the shell command prompt.

If you happen to hit the : key by accident, or decide you don’t actually want to enter an Ex command you can exit out of Command Mode with the <Esc> key, just like exiting Insert Mode.

Having to type :quit all the time might get a bit tedious. Fortunately most Ex commands have short versions. You can also exit Vim with the :q command.

Vim will not quit if you have unsaved changes in a buffer. Let’s enter some text into a buffer and then try to quit. Press <Esc> to make sure you are in Normal Mode. Now type i to enter Insert Mode. Type anything you want, maybe Hello, Vim!, and then press the <Esc> key again. You are now back in Normal Mode and there is some new text in the buffer. Now type :q to try and quit Vim.

Vim Error Messages
Vim Error Messages

Vim notifies you that there has not been a write of the buffer since it was last changed. It also informs you that you can override the error by adding a ! character. We don’t actually need to save this text so lets try Vim’s suggestion. Type :q!. Vim will exit and throw away any changes in the buffer that you had made.

Opening a File

When you type vim at the command prompt Vim starts without any open files. There are ways to open files while you are in Vim, but the easiest way to open a file is to supply the file path as an argument to the vim command. If you wanted to edit the Z Shell configuration file you could enter this command.

$ vim ~/dotfiles/zsh/.zshrc

That opens the specified file in Vim. You will see some additional information in that status line. The path to the file is shown in double quotes followed by the number of lines and characters in the file. It also shows the line and column number of the cursor location, currently 1,1, and that you are at the top of the file.

Z Shell Configuration File In Vim
Z Shell Configuration File In Vim

If Vim is already started you would use the edit Ex command. You have Vim open now, with the Z Shell configuration file open. Suppose you needed to make a change to the tmux configuration file as well. Just enter :edit ~/dotfiles/tmux/.tmux.conf then press <Return>. The tmux configuration fill will be opened in Vim and ready to be edited. Be aware that you can use <Tab> completion on the file name in the same way you would use completion in the shell.

Just like with the quit command the edit command can be shortened to just :e. So you could have entered the above command as :e ~/dotfiles/tmux/.tmux.conf.

You can also use edit to create files. If the file name you supply to the edit command does not exist Vim will create a new buffer that is attached to the file name you provide, but the actual file will not exist on disk until you write it.

Simple Editing

Now that you have a file open it would be handy to be able to do some editing. I’m going to show the most basic movement commands and a couple ways to get into Insert Mode. This should be enough to get simple configuration file editing done. It will be slow, but it will be enough for now.

To move the cursor around you can use the h, j, k and l keys. You should have the .zshrc file open still. Press the j key a couple times. The cursor will move down a line each time it is pressed. Now press the k key. The cursor moves up a line. Very simple, j moves the cursor down and k moves the cursor up.

Now make sure the cursor is not on a blank line and press the l key a few times. The cursor will move to the right one character at a time each time it is pressed. Pressing the h key will move the cursor to the left one character at a time.

Just those four keys are enough for you to position the cursor anywhere in a file in preparation for an edit. However, they are terribly slow. To start with we will be editing fairly short configuration files, so using j and k to move up and down should not be too bad. Moving a single character at a time on a line will get old very fast though.

Four more simple commands should be enough to help you move faster. The w key will move the cursor to the right one word at a time and the b key will move the cursor to the left one word at a time. The 0 (zero) key will move you to the start of the line and the $ key will move you to the end of the line.

Using some combination of those eight commands you should be able to position the cursor in a file where you need to make an edit. To actually get into Insert Mode to make the edit you can use one of four other commands, i, I, a and A. Yes, there is a difference between the uppercase and lowercase versions of those commands.

The i command stands for insert. Pressing the i key will make Vim enter Insert Mode at the point to the left of the cursor. Pressing the I key will make Vim enter Insert Mode at the start of the current line.

The a command stands for append. Pressing the a key will make Vim enter Insert Mode to the right of the cursor. Pressing the A key will make Vim enter Insert Mode at the end of the current line.

If you enter Insert Mode and the cursor is not positioned exactly where you need it to be you have two options. You can press the <Esc> key, use the movement keys discussed above to re-position the cursor, then re-enter Insert Mode, or you can simply use the regular arrow keys to move the cursor around without leaving Insert Mode.

Most Vim users would say that using the arrow keys is a bad habit, and they are right. For now, while you are still getting used to Vim, don’t worry about it too much. Use the arrow keys when you need to. Over time you will pick up more editing techniques and you will find yourself relying on the arrow keys less and less.

Saving Your Work

No editing session would be complete if you didn’t save your changes to the file. In Vim you use the :write Ex command to save your changes. Every file opened in Vim is stored in a buffer. Any changes you make to the buffer are only stored in Vim. Using the write command will store those changes back to the file on disk.

We haven’t made any changes to the .zshrc file, but we can still save it. Press the : key to enter command mode and then enter write and press <Return>. You will see the file name, line and character counts again, just like when you opened the file., You will also see the written notification that lets you know that the file was saved to disk.

Like the quit command, the write command can be shortened to just :w. It will become second nature after a while to use the :w command on a regular basis.

If you know that you are done editing files you can also write the file and quit Vim at the same time by combining the two operations. Entering :wq will write any changes to the current file and then quit Vim.

Getting Help

The most important Vim Ex command you should know is the :help command. The :help command, which can also be shortened to :h opens a new window in Vim and displays the main Vim help file. The first page of the help file explains how to move around in the help text, how to jump to other help topics and so on. After that short section is a long list of topics on every aspect of using Vim.

You can peruse the topic list to find what you are looking for, but you can also supply the :help command with an argument. For example, if you wanted to learn more about the :quit command you can type :h :quit and the help window will open directly on the :quit topic.

If you are done with the help window simply enter :q to close it. Don’t worry, you won’t exit Vim entirely, just the help window.

Wrap Up

So, to reiterate, the process for editing and saving a single file is as follows.

  1. Run Vim with vim or nvim on the command line
  2. Open a file with the :e Ex command and <Tab> complete the file name
  3. Position the cursor to where you wish to make an edit with h, j, k, l, w, b, 0,$
  4. Enter Insert Mode with i, I, a orA
  5. Edit the file as desired; all keys act as they normally would while in Insert Mode
  6. Return to Normal Mode by pressing the <Esc> key
  7. Repeat steps 3 through 6 until all necessary changes are complete
  8. Save and exit Vim with the :wq Ex command

Update the Dotfiles Project

Vim and Neovim both look for a configuration file when they start. The two programs look in different places and for different default file names though. So, depending on which editor you installed you will need to create the symbolic link in a different way. In both cases we will store our configuration files in the same place.

To start, as always, we will create a new directory in the dotfiles repository to store our configuration file.

$ mkdir ~/dotfiles/vim

Vim Steps

If you installed Vim you will need to create a .vim directory in your home directory. This is where any plugins you install will be located. Make an empty .vimrc file in the dotfiles project and then make a symbolic link to it. (Note that the symbolic link in ~/.vim does not have a preceding dot. If you mistakenly add the dot Vim will not see the configuration file.)

$ mkdir ~/.vim
  $ touch ~/dotfiles/vim/.vimrc
  $ ln -s ~/dotfiles/vim/.vimrc ~/.vim/vimrc

Neovim Steps

If you installed Neovim you might need to create a directory before you can make the symbolic link. Neovim looks for its configuration files in the ~/.config/nvim directory. The ~/.config directory is being used by a number of programs now, so you might already have it. The nvim subdirectory will probably not be created yet, so the following command will take care of either case.

$ mkdir -p ~/.config/nvim

The -p option to mkdir just means to make any missing directories along the way to making the nvim directory. In this case it will create the ~/.config directory if it is missing, and then create the nvim directory.

Neovim looks for its startup configuration file in ~/.config/nvim/init.vim so we will use that file name instead of .vimrc and make the symbolic link to it.

$ touch ~/dotfiles/vim/init.vim
  $ ln ~/dotfiles/vim/init.vim ~/.config/nvim/init.vim

Configure Vim

There are loads of pre-built .vimrc files available on Github. Some people recommend just grabbing one of those files and using it on your own machine. I do not believe this is a good idea, especially when you are just starting out with Vim. Those files tend to have many plugins and settings that you may or may not need, and you will certainly not understand how to use all the added functionality. I suggest going slow with Vim and only adding plugins as you really need them.

That being said, there are actually some simple settings we should add to our configuration file now. There is nothing too drastic here, just a few settings to make Vim work a bit better. I will explain them all as I go along.

Line Numbers

Having line numbers available for every file is a must. I can’t imagine working on code for any length of time and not needing to see the line numbers. This is easy to set, just add the following line to your .vimrc. Note that the double-quote character is the comment character in Vim script files.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Turn on line numbers
  set number

Tabs And Spaces

This section can get a bit contentious, I will explain the settings and let you decide how to best set everything for your preferences. I would suggest keeping tabstop, softtabstop and shiftwidth the same length. Tabstop is exactly what you think, the amount of space used when the <Tab> key is pressed. The softtabstop setting determines how far the cursor is moved when the Tab key is pressed. You can set it to be shorter or longer than tabstop, but there is generally no reason to do so. shiftwidth is how much space is used when you indent or outdent existing text. Make your life simple and set these all to the same value. I write mostly Ruby code, so I have these set to 2. Feel free to set these to 4 or more if your language guidelines dictate it.

The expandtab setting will convert a Tab into space characters. I make no judgments on your preference. Use expandtab on its own to convert Tabs to Spaces, use expandtab! to keep the Tab character.

The autoindent setting does what you would expect when writing code. It automatically indents your code when opening a new block or function.

Setting copyindent is handy for working with other peoples code. When auto indenting a new line it will use the same indent character(s) (Tab or Spaces) that exist on the current line. So, if you are editing a file written by someone who uses Tabs for indenting and you add a new line, it will use a Tab.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Tabs and Spaces
  set tabstop=2
  set softtabstop=2
  set shiftwidth=2
  set expandtab
  set autoindent
  set copyindent

I’ll now slowly tiptoe out of the lava pit of code formatting preferences.

Scrolling

The scrolloff setting is a handy way to keep from having to stare at the bottom of your screen all day. The scrolloff setting tells vim how many lines of context you want to keep above and below your cursor. If you are at the bottom of the file, however, there is no context to show after the cursor. Still, this is a handy setting for most cases.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Keep context above and below the cursor.
  set scrolloff=5

Full Color Mode

There used to be some problems between Vim, tmux and Z Shell where it comes to displaying true colors. It seems to have been pretty much ironed out in the more recent versions of the applications. We do still need to make sure Vim will use true color when we start it though. Add these lines to the file. (Note: If you are using WSL do not add this setting. The WSL Terminal does not support true color mode.)

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Set true color mode.
  set termguicolors

These are all of the simple settings that we will be adding. We do still need to add some configuration settings, but the majority of them will require having a plugin manager setup and working. There are quite a number of different plugin managers in use for Vim, so it can be a bit confusing picking one and figuring it out. The Vim Plugins section will cover getting a plugin manager setup for both Vim and Neovim.

Editor Variable

There are some settings we can add to our .zshrc file that will help with using Vim or Neovim. First, the EDITOR environment variable should be set correctly. At the bottom of the .zshrc file you will find a user configuration section. There should already be a bit of script code that looks like the following.

~/dotfiles/zsh/.zshrc
  # Preferred editor for local and remote sessions.
  # if [[ -n $SSH_CONNECTION ]]; then
  #   export EDITOR='vim'
  # else
  #   export EDITOR='mvim'
  # fi

What this does is allows you to change your editor based on whether or not you are currently in an SSH connection. It probably males sense to keep the true branch set to Vim. Most servers will have Vim installed, and even if you are using Neovim locally there is no real difference in basic usability.

Uncomment the ‘if’ through ‘fi’ lines and set the EDITOR variables appropriately. If you are using Neovim the actual program name is nvim. The mvim shown above is for MacVim, which is not what we are using.

Aliases

If you are using Neovim you might want to add a couple aliases to the .zshrc file.

~/dotfiles/zsh/.zshrc
  # Alias Neovim to the standard name.
  alias vim=nvim
  alias vi=nvim

These will allow you to start Neovim by just using vim or vi.

Vim Plugins

Both Vim and Neovim support Vim script. You have already used Vim script in a limited manner. The Vim configuration file you created is actually Vim script. The set commands you used to configure Vim are also available as commands on the Vim command line. A Vim script can contain functions, create new commands, and add key mappings. If a Vim script is useful to many people it can be bundled into a plugin.

A plugin is just a directory. The directory name is the plugin name. Inside the directory is a doc and a plugin directory. The actual plugin code will be in a .vim file in the plugin directory and any documentation for the plugin is contained in a text file in the doc directory.

In order for the plugin to ba usable by Vim it must be available in the Vim runtimepath. You can manipulate the runtimepath variable within Vim, but that is tedious and error prone. This is where the many Vim plugin managers came into play. They provide a means to automate installing, uninstalling and setting the runtimepath variable for plugins.

Vim 8 and above and Neovim have support for Packages. Packages are a built in way for Vim to manage plugins. Vim will now look for a directory named pack when it starts. The default location of this directory is different for Vim and Neovim, but asside from that difference both editors work the same. Vim will look at ~/.vim/pack, and Neovim will look for ~/.config/nvim/pack.

When Vim and Neovim start they will look in their respective pack directory for any installed plugins. If any are found the runtimepath is automatically updated with the correct path and then the plugin is loaded.

With that rather lengthy description out of the way I can finally get down to actual plugin setup. There is a minimal plugin manager that is written to take advantage of the new Package capabilities in Vim called Minpac. I will walk you through getting it installed and working.

Minpac Setup

We will create a directory to store the Minpac code first. Be sure to create it in the correct hierarchy for Vim or Neovim. When the directory is created change directory into the new directory.

$ mkdir -p ~/.vim/pack/minpac/opt
  $ cd ~/.vim/pack/minpac/opt

Or

$ mkdir -p ~/.config/nvim/pack/minpac/opt
  $ cd ~/.config/nvim/pack/minpac/opt

Now clone the Minpac repository.

$ git clone https://github.com/k-takata/minpac.git

Now that Minpac is installed we just need to update our .vimrc file to load it on startup. Open .vimrc or init.vim, whichever is appropriate for you and add the following lines.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Start Plugins Section
  
  " Initialize Minpac
  packadd minpac
  call minpac#init()

The packadd line adds the Vim package, which we named minpac from the pack directory. Once the package is loaded we call minpac#init() to initialize the plugin.

You should keep regular Vim configuration settings and plugin settings separate in your configuration file. The plugins section is likely to change more often as you add and remove plugins.

Another approach you could take is to separate all of the plugin related code to a separate file. If you would like to go that route simply create a file at ~/dotfiles/vim/plugins.vim. Put the Minpac code above into that file and then add the following line near the bottom of your .vimrc or init.vim file.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  source ~/dotfiles/vim/plugins.vim

Using Minpac

I’ll demonstrate Minpac usage by showing you how to install the color theme used in this book. It is a port of the One theme that is the default theme in Atom. It has a dark and light version, but I prefer the dark theme because it is easy on the eyes.

To install a plugin you add a line to your .vimrc file that calls minpac#add(repo, options). The repo argument is mandatory and should be the username and project name of a Git repository hosted online. The options argument is optional and can be used to supply configuration options to the plugin as it loads. For the theme we want to install add the following line after the minpac#init() line. (Note: If you are using WSL do no add this plugin. There will be a different approach used to set a similar color scheme in the Theme Wrapup section.)

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Load the 'one' color scheme.
  call minpac#add('rakr/vim-one')

Save the file and quit Vim with :wq then restart Vim. When Vim is started again enter the :call minpac#update() Ex command.

That tells Minpac to fetch any plugins that it knows about and install them. If you look at your Vim package directory now you will see that Minpac has created a new directory called start, and inside that directory the vim-one plugin has been installed. It will also update existing plugins. If the Git repository of a plugin you are using is updated with new code the :call minpac#update() command will retrieve the new code so you will always be using the latest version of your plugins.

The start directory is special. Any plugins located in that directory will be loaded automatically by Vim when it starts up. The opt directory is for optional plugins that you do not want to load at startup time.

You might wonder why we put Minpac in the opt directory. The plugin loading process is fairly late in the Vim startup cycle. By putting Minpac in the opt directory and explicitly loading it with the packadd directive we ensure that it is available to use earlier in the startup process.

Removing A Plugin

If you no longer wish to use a plugin you have installed with Minpac you can remove it by deleting the call minpac#add() line from your Vim configuration file. Once you have saved the file, exit and restart Vim. When it is open again enter :call minpac#clean() Ex command.

That will scan your plugins and remove any that are no longer added with minpac#add(). You will be prompted with a yes or no question for each plugin it tries to remove.

Create Helper Commands

You were probably looking at those Minpac commands above and thinking, “I’ll never remember those commands every time I want to change my plugins.”. After this section you won’t have to.

One of the great things about Vim is how configurable it it. One of the things Vim script allows you to do is create your own Ex commands. We will add two new Ex commands to make updating and cleaning your plugins easier.

Open your Vim configuration file, if it isn’t already, and add the following lines after the Minpac init() function call.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Create Minpac helper commands.
  command! PackUpdate call minpac#update()
  command! PackClean call minpac#clean()

The Vim script command command will create a new Ex command that can be used in Command Mode. When you append an exclamation mark to it, as we did above, it redefines the command if it is already defined. When you create a command it must start with an uppercase character.

Save the file and restart Vim. You can now update your plugins or clean out old plugins with the :PackUpdate and :PackClean Ex commands.

Theme Wrap Up

In the last section I had you install the One theme plugin as the color theme that will be used in this book. (Note: If you are using WSL you can skip down to the WSL Theme section.) You probably have noticed that the color theme hasn’t changed yet. There are a few more steps and configuration changes we need to make before the theme will work correctly. We will take care of those changes here, and that will wrap up the majority of the Vim configuration. There will be a couple other plugins and optional settings down the line, but for the most part Vim will be completely setup after this section.

Airline Plugin

The Vim Airline plugin changes the Vim status line to include valuable information, such as the current Vim Mode you are in, the status of the Git Repo if you are in one and many other bits of information. It is configurable as well so you can change the order, layout and colors of the information. The One theme that we will be using has its own theme for Airline, but in order to make use of it we need to install Airline.

Open your Vim configuration file and add the following plugin after the vim-one plugin.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  call minpac#add("vim-airline/vim-airline")

We still need to make Mincap install the plugin, so save the file and restart Vim. Once it is running again use the new command we added in the last section to update the plugins, :PackUpdate.

You should see the status line update with a notification about the vim-airline plugin being installed.

Powerline Fonts

Airline makes use of some special symbols on the status line to make it look a little more streamlined. Not all fonts have the needed glyphs available in their font files, so there are patched fonts that you can install which include the necessary glyphs.

Fortunately there is a Github repository that contains all of the necessary patched fonts and an install script to set them up. You can clone the repo, run the install script to install the fonts, then delete the repo. In your home directory run the following commands.

$ git clone https://github.com/powerline/fonts.git --depth=1
  $ cd fonts
  $ ./install.sh
  $ cd ..
  $ rm -rf fonts

Set The Theme

If you are using Vim you will need to explicitly turn on syntax highlighting. You can turn it on manually in Vim by using :syntax on , or turn it off with :syntax off . You probably don’t want to have to do it by hand every time though, so add this to the Vim configuration file. If you are using Neovim you don’t need this; syntax highlighting is on by default, but it also doesn’t hurt anything if it is included.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  syntax on

Now that the status line plugin is installed, and the patched fonts are available and syntax highlighting is turned on we can actually tell Vim to use the theme. In your Vim configuration file add the following lines.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  let g:airline_theme="one"
  colorscheme one
  set background=dark

First we set a variable for Airline to let it know to use the One theme. Then we tell Vim to use the One theme as well. Finally, setting the background to dark triggers the Dark version of the One theme to be used. The One theme actually comes with a Dark version and a Light version. If you would prefer the Light version change the background setting to light.

As usual, you need to save the file and restart Vim to see the changes. Once you have done that open a source code file you already have, or one of the dotfiles configuration files to see the syntax highlighting.

Vim One Theme (Dark Version)
Vim One Theme (Dark Version)

WSL Theme

The Windows Subsystem for Linux uses the built in Window Terminal. It is possible to use third party terminals with WSL, but setting them up to work correctly is beyond the scope of this book. I have found a 256 color scheme inspired by the One dark theme that can be used in WSL.

This color scheme is not added as a plugin. It is a regular Vim color scheme. You can add third party color schemes to Vim by adding them to a colors directory. The directory name is the same for Vim and Neovim, but the location is different.

Vim Colors

$ mkdir ~/.vim/colors

Neovim Colors

$ mkdir ~/.config/nvim/colors

The color scheme is stored on Github, so we will clone the repository, move the color scheme file to the correct location, then remove the repository. Make sure you are in your home directory and run the following commands.

Vim

$ git clone https://github.com/gosukiwi/vim-atom-dark
  $ mv vim-atom-dark/colors/\* ~/.vim/colors
  $ rm -rf vim-atom-dark

Neovim

$ git clone https://github.com/gosukiwi/vim-atom-dark
  $ mv vim-atom-dark/colors/\* ~/.config/nvim/colors
  $ rm -rf vim-atom-dark

Now that the color scheme files are in place it is just a matter of updating the Vim configuration file to use it by default.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/.init.vim
  colorscheme atom-dark-256

Save the file and reload Vim and you should see an approximation of the One dark theme.

Atom Dark Vim Theme
Atom Dark Vim Theme

There has been quite a lot of configuration steps for Vim, but we are in a very good position now to learn Vim and have it be a pretty comfortable experience. Take some time to recharge if you like and prepare for a more in-depth Vim tutorial.

Vim Modes

Vim works in what are known as Modes. I covered this a bit in the Basic Vim section, but I’d like to go into a little more depth here. There are actually six modes in Vim. Normal, Insert, Visual, Select, Command and Ex mode. Neovim has an additional Terminal Mode that provides a complete terminal inside a Vim buffer.

You have already worked with three, Normal, Insert and Command mode in the Basic Vim section. In the following sections I will go over each mode in more depth, except for the Select and Ex modes. The use cases for those modes are very specialized, so you probably will not need to use them often, especially as you are just getting started with Vim.

Normal Mode

When Vim starts it is in Normal Mode. Everything you type will be interpreted as Normal Mode commands, including the commands that make Vim enter a different mode.

Movement Commands

You have already learned some of the movement commands, but I will cover them here again briefly. The most basic movement commands are h, j, k, and l. They move the cursor one character left, one line down, one line up and one character right respectively.

Moving one character at a time within a line of text can be very slow, so there are other ways to move more quickly. The w command moves the cursor one word right while the b command moves the cursor one word left. The W command will move one WORD to the left and the B command will move one WORD to the right. A WORD in Vim is always delimited by white space, whereas a normal word can be delimited by whitespace, parentheses and so on. As an example, suppose your cursor was on a Ruby function definition.

Keystrokes Results
def perform_billing_actions(user)
w def perform_billing_actions(user)

Using the w command causes Vim to check for additional delimiter characters, so you wind up at the open parentheses.

Keystrokes Results
def perform_billing_actions(user)
W def perform_billing_actions(user)

If you instead used the W command the cursor would end up on the close parentheses because it is moving to the next whitespace character.

The w and b commands move to the beginning of the word. There is also an e and E commands which will move to the end of a word and end of a WORD respectively. Suppose you have written a blog in Rails. There will likely be some code to get an ordered list of blog posts similar to the code below.

Keystrokes Results
@posts = Post.published.order(‘published_at DESC’)
w @posts = Post.published.order(‘published_at DESC’)
5w @posts = Post.published.order(‘published_at DESC’)
b @posts = Post.published.order(‘published_at DESC’)
e @posts = Post.published.order(‘published_at DESC’)
E @posts = Post.published.order(‘published_at DESC’)

You can see the e command will put you at the end of the current word and the E command will move you over special characters until whitespace is encountered. This can be handy if you want to add text directly to the end of a word.

You can move the the start of the current line with the 0 (zero) command and to the end of the current line with the $ command. You can move forward one sentence with the ) command and backwards one sentence with the ( command. Similarly, moving forward one paragraph can be accomplished with the } command and backward one paragraph with the { command.

For larger movements within a file you can use gg to move to the top of the file and G to move to the bottom of the file. If you know the line number you want to move to you can enter the number followed by G. For example, to get to line 50 you would press 50G.

Prefixing a command with a number is possible with many Vim commands. You know the j command moves the cursor down one line. If you wanted to move down 5 lines you could use 5j. This works for moving forwards and backwards over words, sentences and paragraphs as well.

Editing

Not all file editing happens in Insert Mode. Insert Mode is great for adding new text, but not ideal for deleting, changing or moving text around. I’ll cover deleting and changing text here, moving text will have to wait until the Visual Mode section.

Deleting Text

Let’s start with the most simple delete command. The x command will delete a singe character under the cursor and the X command will delete a single character to the left of the cursor.

Keystrokes Results
The quick brown fox jumped over the lazy dog.
x The quick brown ox jumped over the lazy dog.
x The quick brown x jumped over the lazy dog.
x The quick brown  jumped over the lazy dog.
x The quick brown jumped over the lazy dog.
6X The quick jumped over the lazy dog.

The x command appears to chew up characters to the right of the cursor and the X command chews up characters to the left.

The two x commands work well for a couple characters here and there, but they aren’t efficient for larger deletions. This is where the d command comes in. The d command is really an Operator. It doesn’t perform an action on its own. It has to be combined with a Motion or Text Object. I will cover Vim Operators in depth in the Operators section. To delete from the cursor to the end of a word you would use the dw command. It is important to note the ‘from the cursor’ part of that description. If the cursor happens to be on the first character of the word the dw command will delete the whole word. If the cursor is on the third character of the word it would only delete from there to the end.

This is where the i and a modifiers come into play. When used with operators i stands for inside and a stands for around. Combining those modifiers with the d operator you get diw which means delete everything within the word boundary. This allows you to delete an entire word regardless of where the cursor is positioned in the word. The daw version deletes the entire word and whitespace around the word.

Keystrokes Results
The quick brown fox jumped over the lazy dog.
diw The quick  fox jumped over the lazy dog.

You can see that the diw command deletes only the word. Any space after the word is left untouched. This is helpful if you mean to replace the word with a different word. You could then enter Insert Mode, type the new word, then <Esc> back to Normal Mode. There is actually a faster way to complete that kind of edit, the c Operator, which I will get to shortly.

Keystrokes Results
The quick brown fox jumped over the lazy dog.
daw The quick fox jumped over the lazy dog.

The daw version also removes the whitespace after a word, leaving the cursor resting on the start of the next word. This is best if you simply want to remove an entire word and do not need to add anything else at that point in the file.

You can delete an entire line with the dd command. You can delete from the cursor position to the end of the line with d$ or to the start of the line with d0 . To delete from the cursor position to the start of the file would be dgg or to the end of the file with dG.

Changing Text

The r command replaces a character. It you position the cursor on the character you wish to replace, press the r key then the new character.

Keystrokes Results
The quick brown box jumped over the lazy dog.
rf The quick brown fox jumped over the lazy dog.

You can also use a count with the r command, but the result only useful in a small set of cases.

Keystrokes Results
The quick brown box jumped over the lazy dog.
3rf The quick brown fff jumped over the lazy dog.

It doesn’t allow you to replace different characters, it just repeats the given character the {count} number of times.

The y Operator yanks text into a kind of clipboard. It is similar to the copy command in GUI based editors. Note that the d operator works the same way as the y operator. It is like the cut command in GUI editors. The deleted text is stored and can be re-inserted into the file via one of the p commands.

Vim doesn’t really use a clipboard, it uses what are called registers. When you use the y, d and p commands they reference the unnamed register. The unnamed register can only hold a single piece of text at a time, so any other yank or deletion after the first will replace the contents of the register. Vim also has named registers, which will allow you to store multiple pieces of text, but using them is a bit out of context for this section.

Like the d operator the y operator requires a motion. You can yank words, forwards and backwards with the w and b motions.

The yanked text can be re-inserted into the file with the p command. The lowercase p command will insert the yanked text to the right of the cursor position. The uppercase P command will insert the yanked text to the left of the cursor position.

Keystrokes Results
The quick brown fox jumped over the lazy dog.
yaw The quick brown fox jumped over the lazy dog.
w The quick brown fox jumped over the lazy dog.
P The quick quick brown fox jumped over the lazy dog.

The yaw command yanks the word quick and the trailing space into a register. Then use the w command to move forward to the next word. Finally, use the P command to insert the word before the cursor position.

You can yank an entire line with the yy command. If you need to duplicate a line so you can make a small change use yyp. That will yank the current line and immediately copy it below the current line. You can yank from the cursor position to the end of the line with y$ or to the start of the line with y0.

Undoing Changes

If you make a change, or a series of changes that you don’t like you can undo them with u. Pressing u once will undo the last change, continuing to press it will undo successively earlier changes.

If you then decide you do want those changes, or you undo too far back in the edit history you can redo the changes with <C-r>. It would have been nice for the redo command to be simply r but that character is already being used as the replace command.

Searching

If you think about it, searching is a kind of movement. Particularly in Vim because it automatically moves the cursor to the first search hit. There are a number of ways to search for text in Vim. The simplest is the f command and its brother F. Think of it as the find command. It works on a single line of text. The f version will search forward from the cursor along the line of text, and the F version will search backwards from the cursor.

They are especially well suited to quickly move the cursor to a particular spot in a line of text so you can then make an edit. Suppose you mistakenly typed jumped twice and wanted to fix the problem.

Keystrokes Results
The quick brown fox jumped jumped over the lazy dog.
fj The quick brown fox jumped jumped over the lazy dog.
daw The quick brown fox jumped over the lazy dog.

First we find the next j character, which positions the cursor on the word jumped. Then we use the daw command to delete the first occurrence of jumped and its trailing whitespace.

Once you find a character you can move forwards to other occurrences of that character with the ; (semicolon) command. You can move backwards with the , (comma) command. Keep in mind that the original direction of the search sets the direction for the ; and , commands. So, if you had used the F command to search backwards from the cursor the ; command will continue to move backwards and the , command would move forwards.

The two f commands search a single line. If you need to widen your search you can use the / and ? commands. These two commands will open up the command line and allow you to enter a regular expression. Don’t let the term regular expression freak you out. You can enter a crazy regular expression, but you can also just type a word you need to find.

The / version of the command will search forward through the file from the cursor. As you type the regular expression you will see search hits highlighted in the file. The more you type the more refined the search hits will become. When you press the <Return> key the cursor will be moved to the first occurrence of the search.

The ? version of the command works the same, but it searches backwards through the file from the cursor position.

If there is more than one search hit they will all be highlighted and you will be able to move from one to the next with the n and N commands. The n command will move you to the next search hit, which can be forward or backward through the file, depending on the version of search you started with. Similarly the N command will move you to the previous search hit.

If you continue to move through search hits with the n or N commands you will eventually reach the end or the beginning of the file. Pressing n or N again at that point will wrap you around to the other end of the file. Vim will notify you of this on the command line, stating ‘search hit BOTTOM, continuing at TOP’ or vice-versa.

Insert Mode

Insert Mode lets you type freely to create new text. While in Insert Mode your keyboard will act as you expect. Typing a character key will insert that character into the buffer. The <Backspace> key will delete characters, the <Return> will create a new line, and so on. There are some Vim commands available to you while you are in Insert Mode, and I will cover some later in this section, but mostly what I will cover here are the different ways to change from Normal Mode to Insert Mode.

Back in the Basic Vim section I told you about the insert and append commands. Just as a brief recap; the i command puts you into Insert Mode to the left of the cursor and the I command puts you into Insert Mode at the start of the line. The a command puts you into Insert Mode to the right of the cursor and the A command puts you into Insert Mode at the end of the line.

Those commands make intuitive sense if you think about it. The lowercase version of each command doesn’t move the cursor, they just determine which side of the cursor will be active. The uppercase versions are larger moves. The insert will happen some distance away from the current cursor position.

Open

Another way to get into Insert Mode is the open command. Like many other Vim commands there is an uppercase and lowercase version of the command. The lowercase version, o will create a new line below the cursor and put you into Insert Mode. If you are editing code it is smart enough to auto-indent the new line for you.

Keystrokes Results
typedef struct {
  int x;
} Point;
o typedef struct {
  int x;
   
} Point;
int y;<Esc> typedef struct {
  int x;
  int y;
} Point;

The nice thing about the o command is it doesn’t matter where the cursor is on the current line. You don’t have to move to the end of the line and press return. Just press the o key and you are ready to type your new line in.

The O command does the same thing, but above the current line. Like the o command it also will auto-indent the line based on the surrounding source code.

Delete Then Insert

The commands covered so far simply move you from Normal Mode to Insert Mode, but in different directions and at different lengths around the cursor. The following commands will actually delete some text and then enter Insert Mode. This is handy for replacing words, line, sentences and so on. You don’t have to delete the text first, then enter Insert Mode to replace it. You can delete and move to Insert Mode at that same time.

The s command deletes some text and then enters Insert Mode. The lower case version, s deletes a single character under the cursor, the uppercase version, S deletes an entire line.

I don’t find much use for the lower case version of the command, but replacing a line is very handy. Suppose you are editing the Point structure shown above and want to change the types to float.

Keystrokes Results
typedef struct {
  int x;
  int y;
} Point;
S typedef struct {
   int y;
} Point;
float x;<Esc> typedef struct {
  float x;
  int y;
} Point;

Then you can repeat the process on the next line.

In this case, however, there is a better method. The S command is great if you need to replace the entire line. In the case above all we really need to replace is the type name. This can be accomplished with the change Operator.

Like the delete Operator, the change Operator, c, requires a Motion command or Text Object to let it know how much text to delete. Once it has deleted the selected text it will enter Insert Mode.

Keystrokes Results
typedef struct {
  int x;
  int y;
} Point;
ciw typedef struct {
   x;
  int y;
} Point;
float<Esc> typedef struct {
  float x;
  int y;
} Point;

The cursor is sitting within the word we want to change. The ciw command changes inside the word, leaving whitespace after the word alone. The we just need to type float and <Esc> out of insert mode.

Paste Text

Normally when using the p command with deleted or yanked text you are in normal mode. There are occasions when it would be handy to delete or yank some text, enter Insert Mode and then insert the text from the register.

You can do this with the <C-r>0 command. The <C-r> portion gives you access to the registers. The yank register is accessed with the 0 (zero) command. You can also use the <C-r> command with other registers. For example, the <C-r>" command would put the contents of the unnamed register into the buffer. To see the contents of Vim’s registers enter the :reg[isters] Ex command. The command area will expand to show the text in each register. Note that the leading double quote character is not used with the <C-r> command, only the second character is needed.

I’ve talked about a number of Operators now, d, y, and c. There are some other Operators as well and they all work the same way. They are different from other Vim commands in that they require additional information before they can complete their task. The next section will go into more depth on how to use them.

Operators

Much of the power of Vim comes from the use of operators. Becoming proficient with operators will make many editing tasks much faster. An operator does not perform a command on its own. It must be combined with an optional range modifier and a Motion, or a Text Object. The basic usage is shown in the following table.

Operator Modifier Motion / Text Object Action
d i w Delete inside word
c h Delete left of cursor and insert
y a s Yank around sentence

All of the movement commands can be used in the Motion portion. This means you can cG change everything from the cursor to the end of the file. You can ygg, yank everything from the cursor to the start of the tile.

Text Objects

I have not talked about Text Objects yet. Text Objects are bits of structure in text that Vim understands. For example there is an s Text Object that causes an operator to work on a sentence. There is a paragraph Text Object, p, which causes an operator to work on a paragraph.

It is important not to confuse Text Objects with other Normal Mode commands. Vim will only recognize p as the paragraph Text Object if one of the operator commands has already been entered. Otherwise it will just be the put command as usual. Here is a more complete list of Text Objects.

Key Text Object
w Word
s Sentence
p Paragraph
[ Text within a pair of brackets
( Text within a pair of parentheses
{ Text within a pair of braces
< Attributes within an XML or HTML tag
Text within a pair of single quotes
" Text within a pair of double quotes
t Text within an XML or HTML tag block

The power of operators might be a little clearer now. With these additional Text Objects you can now do things like ci{ which will remove everything inside a pair of braces and put you into Insert Mode so you can enter new code. Or copy the text of a string with yi".

The difference between the < and t Text Objects might not be obvious. The < Text Object operates on the text between the < and > characters of an XML or HTML tag. Suppose you have a <p> HTML element with a class name that you want to change to a <div>.

Keystrokes Results
<p class=“bold”>
ci< < >
div<Esc> <div>

The t Text Object, on the other hand, operates on the text between the opening and closing XML or HTML tag. For example, suppose you want to change the text within a <p> HTML element.

Keystrokes Results
<p class=“bold”>Important Notification</p>
cit <p class=“bold”> </p>
Warning!<Esc> <p class=“bold”>Warning!</p>

Additional Operators

The c, d, and y operators are the most used, but there are a number of other helpful operators.

Operator Function
g~ Swap the case of affected text
gu Make affected text lowercase
gU Make affected text uppercase
> Shift affected text right
< Shift affected text left
= Autoindent affected text

Again, these operators work with movement commands and Text Objects. You already know you can daw (delete around word), now you can also gUaw (uppercase around word).

Especially helpful for code editing is the ability to re-indent code you move around. With the < and > operators you can >i{ (indent inside braces) or <i) (outdent inside parentheses). Need to re-indent an entire file? Use gg=G to go to the top of the file, enable the autoindent operator and have it affect the entire file by moving to the bottom of the file.

The default Operators and Text Objects that come with Vim are few. Even so, there is quite a lot of editing power packed into the defaults. It is also possible to create new Operators and Text Objects in Vim. I will discuss a plugin that adds an operator for commenting or uncommenting portions of text in the Editing Things section. Be aware that there are other plugins available that provide new Operators and Text Objects. You can also create your own if you were so inclined. Just another one of the many ways that Vim shows it’s power.

Visual Mode

Vim’s Visual Mode will look familiar if you are used to normal editors. It allows you to visually select sections of text. The text will be highlighted and you can perform actions on the text using most of the Normal Mode commands.

Be aware that Vim’s Visual Mode does not act the same as selected text in a normal editor. In a normal editor, if you wished to replace a word you would select the word and then just type the new word which would replace all of the selected text with the word you typed.

In Vim, once you have selected a section of text you are not automatically in Insert Mode. You can’t just start typing to replace the selected text. Instead you would use a regular Normal Mode command to operate on the selected text. To achieve the same functionality as a regular editor you would use Visual Mode to select the desired text, then press c to to remove the text and enter Insert Mode. At that point you could type the replacement text.

You activate Visual Mode with the v command. Vim changes its status in the status line to -- VISUAL --. Now you can move the cursor using any of the Normal Mode movement commands. As you move the cursor you will see text being highlighted. The highlighted text is what will be acted upon when you perform any kind of editing task. You can delete, yank, re-indent or any other edit and it will only affect the highlighted text. Once you perform an action, such as yanking, on the highlighted text you will be returned to Normal Mode.

An example might help here. Suppose you had a function named run_billing_actions and you wanted to create another function named init_billing_actions. If you try to select the function name, with something like yiw you would get the entire function name because the underscores are not word delimiters. Instead you could use Visual Mode to select just the portion of the function name you want.

Keystrokes Results
def run_billing_actions()
  # Some code…
end
fb def run_billing_actions()
  # Some code…
end
vfs def run_billing_actions()
  # Some code…
end
y def run_billing_actions()
  # Some code…
end

First, position the cursor where you wish to start the selection. In this case we use the find command and search for the b character in billing. Then activate Visual Mode and find the s character at the end of actions. That highlights the text we want. Finally yank the highlighted text. You will now be back in Normal Mode and you can paste the text where you need it.

If you enter Visual Mode and decide you don’t actually need to select any text you can exit Visual Mode by pressing the <Esc> key or by pressing v again. You will be returned to Normal Mode and no changes will have been made to the file.

Visual Mode Types

There are actually three variations of Visual Mode. The v command enters character-wise Visual Mode. To activate line-wise Visual Mode use the V command. Finally, use <C-v> to activate block-wise Visual Mode.

The difference in the three kinds of Visual Mode revolves around how the text is selected. When you activate character wise Visual Mode the selection of text operates much like you would expect. The cursor can be moved one character at a time and any distance the cursor moves from its starting point highlights text between the two points.

If you activate line-wise Visual Mode with the V command you can only select whole lines. In fact, just activating line-wise Visual Mode will immediately highlight the line the cursor is on. Moving up or down in the file will highlight the entire line as you move.

Block-wise Visual Mode allows you to select blocks of text across lines. This is handy if you have some lined up text that you need to only change a portion of. For example, suppose you have some HTML list elements with a class that you would like to change.

<li class="bold">Item One</li>
  <li class="bold">Item Two</li>
  <li class="bold">Item Three</li>

If you start character-wise Visual Mode and use the j command to move down a line you will end up with too much text highlighted.

Instead you would use block-wise Visual Mode to select just the desired text.

Keystrokes Results
<li class=“bold”>Item One</li>
<li class=“bold”>Item Two</li>
<li class=“bold”>Item Three</li>
<C-v>jj <li class=“bold”>Item One</li>
<li class=“bold”>Item Two</li>
<li class=“bold”>Item Three</li>
lll <li class=“bold”>Item One</li>
<li class=“bold”>Item Two</li>
<li class=“bold”>Item Three</li>
c <li class=“ ”>Item One</li>
<li class="“>Item Two</li>
<li class=”">Item Three</li>
extra-bold<Esc> <li class=“extra-bold”>Item One</li>
<li class=“extra-bold”>Item Two</li>
<li class=“extra-bold”>Item Three</li>

First enter block-wise Visual Mode and then move down two lines. You can see that only a single column of text is highlighted. Next use three l commands to move right three characters to select the rest of the word. It should be clear now why this is called block-wise Visual Mode. You select blocks of text that can span over a number of lines. Now use the c command to remove the selected text and enter Insert Mode. At this point you might be a bit disoriented. When you enter Insert Mode the three line selection disappears and you can only type on the first line where you started your selection. Don’t worry, just enter the new text. When you use <Esc> to exit Insert Mode the text you typed will be copied to the other lines.

Command Mode

Vim’s Command Mode is accessed by typing the : key. That will open a command line at the bottom of the Vim window. This command line is similar to a shell command line. You can enter Vim commands and press <Return> to execute them. You can exit Command Mode and return to Normal Mode at any time before pressing the <Return> key by pressing <Esc>.

For historical reasons the Vim commands you use in Command Mode are called Ex commands. This is because Vim was derived from another editor called Vi and Vi was derived from an editor called Ex. You have already used some Ex commands. The :w[rite], :e[dit] and :q[uit] commands.

There are Ex commands to perform pretty much every task in Vim, from opening and saving files to splitting windows, moving between open buffers, searching for text and even executing shell commands.

There are also a number of editing tasks that can be performed with Ex commands. They overlap with Normal Mode commands, but in some situations the Ex commands can be more powerful. The primary difference between using a Normal Mode command and an Ex command is cursor position. Suppose you wish to delete a line in Normal Mode. First you need to position the cursor on the line you wish to delete, then use the dd command. Many of the Ex commands take line numbers or ranges of line numbers. To delete a line in Command Mode you would use the delete Ex command with the line number you wish to delete. Something like :5delete, which could be shortened to :5d, to delete line number 5. Using the Ex command doesn’t require positioning the cursor first.

You can also specify a range of lines by specifying the start line followed by a comma and then the ending line. If you wanted to delete lines 10 through 15 you could use :10,15d. There are other ways to specify a range of lines for an Ex command. You can make a Visual Mode selection and use the start and end of the selected text as the range, you can also specify a range as regular expression pattern. These techniques are a bit advanced and won’t be covered in this book. Just be aware that there are many ways to specify a range of text for Ex commands.

Some other editing Ex commands are:

Command Action
:[range]delete [register] Delete text in the range and store in a register
:[range]yank [register] Yank text in the range and store in a register
:[line]put [register] Put text from specified register after the given line
:[range]copy [line] Copy text in the range below the line specified
:[range]move [line] Move text in the range below the line specified
:[range]join Join the lines specified in the range into a single line

Run Shell Commands

You can run regular shell commands from within Vim by prepending the command with :! . For instance, if you wanted to know the current directory you could enter :!pwd. That will run the pwd command in the shell and show the results in the Vim command line area.

The % character represents the current file on the Vim command line. You can use that to pass the current file to the shell program. Suppose you wanted to get a word count of the file you are working on. Just enter :!wc -w %.

You can also use the output of a shell command to populate the current buffer. In order to do this you use the :read Ex command. If you wanted to get a list of files in the current directory into a buffer you could use :read !ls. It works in the other direction as well. You can use the contents of a buffer as input to a shell command with the :write Ex command.

Buffer Management

You may have noticed already that when I refer to a file in Vim I call it a buffer. This is Vim’s nomenclature. A file on disk and a buffer in Vim are separate entities. When you :edit a file it is loaded into a buffer. When you :write the file the buffer is saved back to disk.

It is possible, and quite reasonable, to have multiple buffers open in Vim. Every time you :edit a new file it creates a new buffer in the buffer list. It may look like the previous buffer disappears, because the new buffer replaces the current buffer in Vim, but all of the buffers are available still. You can list all of the open buffers with the :ls Ex command. Let’s see it in action.

Start Vim if you don’t already have it started. Now open a couple files. How about the Z Shell and tmux configuration files.

:e ~/dotfiles/zsh/.zshrc
  :e ~/dotfiles/tmux/.tmux.conf

You should only be able to see the .tmux.conf file because it was opened last. Now use the :ls Ex command. The command line area will expand to show the list of buffers Vim is maintaining.

Buffer List
Buffer List

You will also see a prompt at the bottom of the list that lets you know you can either enter another command, or press ENTER to close the buffer list. Each buffer is numbered, and has different symbols next to the number. The number can be used with other buffer commands, which I will get to in a minute. The symbols have different meanings. The % symbol marks the buffer that is currently visible in the window. The # symbol marks the alternate buffer. You can switch between the current buffer and the alternate buffer quickly using <C-^>. Try it now. You can hold down the control and shift keys and tap the ^ key to cycle between the two buffers quickly.

You might also see a plus sign between the buffer number and the file name. This means that the buffer has modifications that have not been saved to disk.

Another way to activate a different buffer is to use the :buffer Ex command, which can be shortened to just :b. To switch to the buffer numbered 1 you can enter :b 1, or :b1. The space between the command and the buffer number is not required.

You can also specify part of the file name to the :buffer command and use tab completion to finish it. Try :b.tm<Tab><Return>. The full file name will be completed and Vim will switch to the buffer for the tmux configuration file.

Both of those methods for switching buffers requires you to either know the buffer number, by using :ls, or remember part of the file name. Another way to move through Vim’s buffer list is with the :bn[ext], :bp[rev], :bf[irst], and :bl[ast] Ex commands. These commands all behave exactly as you would expect. The :bnext and :bprev commands move to the next or previous buffer in the list relative to the current buffer. You will roll around to the beginning or end of the list if necessary. The :bfirst and :blast commands will activate the first or last buffer in the list.

Window Management

Those buffers that we worked with in the last section were all displayed in a Vim Window. When you start Vim there is a single window open, but you can open additional windows so you can see multiple buffers at the same time. You create additional Vim Windows by splitting the current window.

To create top and bottom windows (horizontal split) you use the <C-w>s command. All of Vim’s window related commands start with <C-w> which should be easy to remember (w for window). The s part of the command can be remembered as split. This is consistent with the Ex command for the same operation, :split.

To create left and right windows (vertical split) you can use the <C-w>v command. Again, there is a matching Ex mode command named :vsplit.

When you create a new window, either horizontally or vertically, the buffer in the current window is duplicated in the new window. This can be handy if you are working on a long file and need to see different parts of it at the same time.

There are other times when you need to work with two different files at the same time. There are two ways to handle this. You can use the <C-w>s or <C-w>v command to create the desired split window. The current file will be open in both windows. Now use the :edit command to open the other file you wish to work with.

The other way to accomplish this task is to use the Ex commands. Both :split, and :vsplit take a file name argument. This approach is probably faster if you know you intend to work with a different file in the split window. Just enter :split [path to file]<Return> and the specified file will be open along with the existing file. You can also use tab completion to help out with entering the file name.

Window Navigation

Now that you have multiple Vim Windows open you need a way to move between them. You can use <C-w>w to cycle through all of the open windows. This also works as <C-w><C-w>. In other words, hold down the control key and press w, then hold down the control key and press w again. It looks ugly printed out, but it becomes very natural to press and hold the control key and then just tap w a couple times to move to the next window. If you only have two windows open it will just toggle between them, one after the other.

If you have many windows open or want more control over which window you move to you can use <C-w>h, <C-w>j, <C-w>k, and <C-w>l to move to the left, lower, upper or right window from the currently active window respectively. This should be easy enough to remember because it is the same directions as the Normal Mode movement commands, but prepended with the window movement prefix, <C-w>.

Terminal Mode

Neovim provides another mode beyond the six regular Vim modes. It is Terminal Mode. In both Vim and Neovim you can execute shell commands from Command Mode with the :!{cmd} command, but interacting with the output of the command can be tricky.

If you are using Vim or Neovim inside the terminal, as we are here, you can also suspend it with <C-z>, which will put Vim in the background and return you to the shell. You can then run any shell commands you like. You would return to Vim with the fg command which would return Vim to the foreground.

You may also have a tmux window open specifically for using the shell. With just a couple keystrokes you could activate the console window, perform any tasks you need to and then return to Vim just as easily.

Why would you need another way to interact with the shell? The Neovim Terminal Mode does allow for some interesting uses. Having a terminal in a Vim buffer allows you to navigate through the shell output the same way you would a regular text file. You can yank text to be copied to other buffers, you can use the full power of Vim to edit command lines, you can even open a file under the cursor in a new buffer.

Open a Terminal Buffer

You use the :terminal Ex command to open a Terminal buffer. Note the terminology here. There is a difference between a Terminal buffer and Terminal Mode. The Terminal buffer is similar to a file buffer. A file buffer is showing the contents of the file on disk. A Terminal buffer is showing the contents of the shell process. Terminal Mode, on the other hand, is similar to Insert Mode in that it allows you to actually send commands to the shell process running behind the Terminal buffer.

When you open a Terminal buffer it starts out, like most buffers, in Normal Mode. You can use all of the Normal Mode commands you are used to. Pressing the i, a, I or A commands will put you in Terminal Mode. The cursor will move from wherever it happens to be in the buffer to the command prompt. Now you can enter any shell commands you like. Pressing <Return> will execute the command. You will stay in Terminal Mode until you use <C-&gt;<C-n> to return to Normal Mode.

If you are like me, however, you will probably keep jabbing the <Esc> key when you want to return to Normal Mode. You can make <Esc> work for Terminal Mode as well with a key mapping. There are cases where you actually want the <Esc> to be sent to the command running in the shell. To accomplish that we’ll use another key mapping that will send the <Esc> through to the shell. Add the following code to your Vim configuration.

~/dotfiles/vim/.vimrc or ~/dotfiles/vim/init.vim
  " Use <Esc> to exit Terminal Mode and <C-v><Esc> to send <Esc> to the shell.
  tnoremap <Esc> <C-\><C-n>
  tnoremap <C-v><Esc> <Esc>

The ‘t’ in tnoremap specifies that the key mapping is only available in Terminal Mode. The noremap key mapping command prevents recursive key mapping checks. If the tmap command had been used the <C-v><Esc> mapping would recursively check for other key mappings that start with <Esc>. It would find the other key mapping and end up just exiting Terminal Mode which is not what we want.

Two Cursors

There are actually two cursors in a Terminal buffer. I mentioned above that when you enter Terminal Mode with one of the insert or append commands the cursor jumps to the shell prompt. This is not actually true. The shell prompt cursor is always there, it just may not be visible with the color scheme being used. When you are in Normal Mode you have access to the Neovim buffer cursor. You can move it around the entire buffer and perform any editing operations you like. When you enter Terminal Mode the Normal Mode cursor is hidden and the shell prompt cursor is now available.

The position of the Terminal Mode cursor is also not affected by the insert or append command you use to enter Terminal Mode. The i, a, I and A commands all do the same thing, activate Terminal Mode. The shell cursor will be in the same location it was in the last time you left Terminal Mode. To edit the Terminal Mode command line you would use the same line editing commands you use in a regular shell. If you use Emacs line editing you would use <C-e> to move the cursor to the end of the line. If you use Vi line editing you would use $.

Opening Files

I mentioned above that you can open a file in Vim from a Terminal buffer. That is possible, but there is a bit of a wrinkle. Vim has to know the entire path to the file. It can be a fully qualified path or a relative path from the current location.

Suppose you have Neovim open in the dotfiles directory. Open a Terminal buffer with :term, enter Terminal Mode with i and then run the ls command. You should see the directories that have been created and the README.md file that was added when we created the repository. If you wanted to open the README.md file you could <Esc> to get back to Normal Mode, navigate the cursor so that it is somewhere within the file name then press gf. Because the file is in the current directory Vim knows where to find it and it is opened in a new buffer.

Now switch back to the Terminal buffer with <C-^> or by using :ls and :bufferN where N is the buffer number for the Terminal. Enter Terminal Mode again using i and this time list the vim directory (ls vim). You will see the Vim configuration file in that directory. If you <Esc> and try to open the file with gf you will get an error message. (E447: Can't find "init.vim" in path).

Instead of using ls you can use find. Enter Terminal Mode again and this time use find vim/\*. That will find every file in the vim directory and print the relative path to the file. Now you can <Esc> back to normal mode, select the file you wish to open and press gf.

Exiting the Terminal

In a Terminal buffer your local shell is being run as a separate process. It can also be exited like a normal shell process. Start Neovim and create a Terminal buffer with :terminal, now enter Terminal Mode with i. Run a couple commands, perhaps ls and pwd, just to see the shell working. Now enter the exit command in the shell. The shell process behind the buffer exits like a normal shell would. You will see a [Process exited 0] message. At this point you can press the <Esc> key to exit back to Normal Mode and use any information that is still in the buffer, or you can press <Return> which will close the Terminal buffer completely.

If you press <Esc> to return to Normal Mode you can interact with the buffer as you normally would. If you are finished with it you can still enter Terminal Mode, but you can not start the shell again. All you can do is press <Return> to close the buffer.

Summary

This has been a long chapter. There was a lot to cover. Vim is an extremely large topic and no single book can do it justice, but I believe I have given you enough information to get over the initial pain of switching to Vim.

The next chapter is about tying it all together. This is where you will start to see the true payoff of using a completely terminal based development environment. You will see how to use Z Shell, tmux and Vim together to get real world coding sessions done.