Vim Keybindings

Goal Of This Article

This article will serve as a brief introduction to navigating the editor via vim/Neovim keybindings and how to use basic commands.

The keybinding section of this tutorial serves as a shorter, non-interactive substitute to Neovim's interactive tutorial. If you're familiar with vim keybindings, consider skipping forward to the commands section of this article.

This article is mainly for those who wish to learn by reading. If you would like to take your time and learn by doing, consider Neovim's interactive tutorial accessible by typing :Tutor<ENTER> after entering Neovim from the steps listed in the "Keybinding basics" section. Once you've completed the tutorial, feel free to move on to the next article in this series. Otherwise, continue reading.

Conventions For Describing Keybinds

There will be lots of keybindings introduced in this article, shown in the form .... This suggests that you should press these keys in order. For instance, dF3 means you should press then release the d key, F (note the capitalization, either done by SHIFT + f or CAPS LOCK f CAPS LOCK), then the 3 key on your keyboard, in that order.

Sometimes, a functional key should be pressed (and held) in a series of keybind. Any key in < > brackets will refer to that key on the keyboard and not individual letter keys in order. For instance, <CTRL>r means you should press two keys: first press and hold CTRL, then press r, in order.

With notation out of the way, lets begin with modes in the editor.

Modes

Modes in Neovim determine what the keyboard is hooked up to. There are 7 main modes to Neovim:

Vim Keybinding Basics

Vim motions are to be used in normal mode to quickly navigate or modify the file.

Unlike conventional editors, all editing in Neovim could (and should) be done via the keyboard in pure pursuit of editing efficiency (moving your hands away from the home row of keys to reach for your mouse takes time).

A note on human-computer interation

If the goal of a computer is to serve the user, then the user shouldn't be limited on how they "should" interact with the computer. Thus, I recommend first restricting yourself to navigating with efficient keybinds, then interacting with the editor however you want after you are familiar with them so you can find your own style of navigation that's both comfortable and efficient.

Anatomy of a Vim Motion

All vim motion commands come in the following form

<Command> <Count> <Motion>

<Command> and <Count> are not always necessary, but all motions must include a <Motion>. Motions will be covered at length after this section. For now, we'll focus on <Command> and <Count>.

Command

Without this option, the cursor will simply move as specified by the motion.

However, you must specify a command if you wish to perform a certain action other just moving the cursor. There four most commonly used commands

Any motion prepended by a command will perform that command to the text starting at the original cursor location, and ending at the location of the cursor after the motion.

Note that all commands listed above except for Select supports repeating the command letter twice to have the command act on the current line. dd, for instance, deletes the current line. Entering the capitalized character once also supports this behaviour. For instance, D deletes the current line.

Count

<Count> is a number and will repeat the specified command with the specified motion <Count> number of times.

If a <Count> is not included, it will default to 1.

You'll see examples once we cover <Motion>.

Cursor Motion

To move the cursor around, you may use h, j, k, and l to move one character in each cardinal direction

This serves as the basic set of movements. You may notice your cursor can only move to location with characters, and not into empty space.

To remember these,

Note that if prepended by a command, j and k will act on the current and the line in that direction. For instance, dj will delete the current line and the next line.

Horizontal Movements

This section will detail moving along the same line of text.

Although you can navigate your cursor along a single line with repeated h and l presses, this is very slow. A few helpful keybindings are listed below

The above 3 keybinds are illustrated below, where ^ indicates where the cursor will end up

word1 word2 word3; ^ ^ ^ 0 _ $
By-word Movements (w, b, e, ge)

To navigate the start of the next word, press w. Note that this movement will continue to work even at the end of a line by jumping to the corresponding location in the next line.

word1 word2 ... --(w)-> word1 word2 ... ^ ^

The opposite movement to w is b, which will move the cursor to the beginning of the current word or the beginning of the previous word depending on the position of the cursor.

word1 word2 ... --(b)-> word1 word2 ... ^ ^ word1 word2 ... --(b)-> word1 word2 ... ^ ^

To jump to the end of the current word or the end of the next word, use e.

word1 word2 ... --(e)-> word1 word2 ... ^ ^ word1 word2 ... --(e)-> word1 word2 ... ^ ^

The opposite movement to e is ge, which will move the cursor to the end of the previous word. This is certainly the least used of the 4 horizontal word movements introduced.

word1 word2 ... --(ge)-> word1 word2 ... ^ ^

To summarize

Searching Movements (f, F, t, T)

Searching movements move the cursor to the next/previous specified character in the specified direction.

f will move the cursor to the next occurrence of the character typed after it in the forward direction on the same line. If no more of the character exists in this direction on this line, the cursor will not move.

For instance, f= will move the cursor to the next occurence of = on the same line in the forward direction.

pair<double, double> p = {1.0, 2.0}; ^ --(f=)-> pair<double, double> p = {1.0, 2.0}; ^

The opposite movement is F, which will move the cursor backwards to the previous occurrence of the character typed after it.

For instnace, consider F= illustrated below

pair<double, double> p = {1.0, 2.0}; ^ --(F=)-> pair<double, double> p = {1.0, 2.0}; ^

To move to, but not onto the character, use t instead. It will move to the character just before the character specified.

For instance, consider t=

pair<double, double> p = {1.0, 2.0}; ^ --(t=)-> pair<double, double> p = {1.0, 2.0}; ^

The opposite movement is T, illustrated below.

pair<double, double> p = {1.0, 2.0}; ^ --(T=)-> pair<double, double> p = {1.0, 2.0}; ^

Similarly, notice the cursor sits one character after the = sign.

As a summary

where * is the character you type after the search command.

Say you wish to repeatedly move forward through many = signs on the same line. Although you may repeatedly press f=, this is tiresome. Instead, you can repeat the last of the f, F, t, or T movements with ; and move in the reverse direction with , (comma). For isntance,

p = q = r = s = t = {1.0, 2.0}; ^ --(f=)-> p = q = r = s = t = {1.0, 2.0}; ^ --(;)-> (repeats f=) p = q = r = s = t = {1.0, 2.0}; ^ --(;)-> (repeats f=) p = q = r = s = t = {1.0, 2.0}; ^ --(,)-> (equivalent to F=) p = q = r = s = t = {1.0, 2.0}; ^ --(,)-> (repeats F=) p = q = r = s = t = {1.0, 2.0}; ^

Note that the reverse movement will default to the reverse of the original. That is, f reverses with F, and t reverses with T.

You can also initiate a movement with a backward movement (F of T), which result in the repeat movements triggered by ; to be searching backwards, and the reverse movements triggered by , to be searching forwards.

Bracket matching (%)

Another useful searching movement is %, which jumps to the matching bracket to the bracket that's under the cursor. If there is no bracket under the cursor, it will jump to the matching bracket to the next bracket on the current line. This is illustrated below

void print(int num); ^ --(%)-> void print(int num); ^

This works for all kinds of brackets, including (), [], {}, and <>. Note that the matching bracket doensn't necessarily have to be on the same line. The % movement will also work for brackets on different lines, such as a Javascrip object like the following:

time = { "hour": 12, "minute": 30, "second": 23 }

Further, it correctly identifies nested brackets. For instance

( ( ([()]) ) ) ^ --(%)-> ( ( ([()]) ) ) ^

This is particularly useful for finding mismatched brackets in a file.

Vertical movements

Aside from the j and k keys to move the cursor up and down the file, here are a few additional motions that deal with vertical movements.

To move the cursor to the very top of the current view of the document, use H, abbreviated from "High". Similarly, use M for the middle line of the view, and L, respectively abbreviated from "Middle" and "Low."

These motions are illustrated below. Say your view comprises of line 1 to line 10.

Line 1 <-- (H) Line 2 Line 3 Line 4 Line 5 <-- (M) Line 6 Line 7 Line 8 Line 9 Line 10 <-- (L)
Scrolling (g, gg, <CTRL>f/d/d/u/y/e)

To quickly navigate to the first or last line of a file, consider using the following

To remember these two movements, notice g (the character) looks like a balloon, which floats upwards in the direction of the beginning of the file, while G is a popped balloon and falls to the end.

Note this scrolling action (and all other scrolling actions) is instant and there are no transitions, which can be disorienting might need some getting used to.

To scroll by full pages, consider using the following

These are abbreviated from "forward" and "back".

Note that each of these scrolls will leave two lines in common between each scroll, as illustrated below (each view represents how much of the file is currently displayed in the window of the editor).

Line 1 Line 2 ──────╮ Line 3 │ Line 4 │ Line 5 │ View after <CTRL>b Line 6 │ Line 7 │ Line 8 ───╮ │ Line 9 ───┼──╯ Line 10 │ Line 11 │ Original view Line 12 │ Line 13 │ Line 14 ──┼──╮ Line 15 ──╯ │ Line 16 │ Line 17 │ Line 18 │ View after <CTRL>f Line 19 │ Line 20 │ Line 21 ─────╯ Line 22 Line 23 Line 24

To scroll by half pages, use the following

These are abbreviated from "down" and "up". The change in view is illustrated below

Line 1 Line 2 ───╮ Line 3 │ Line 4 │ Line 5 │ View after <CTRL>u Line 6 ───┼──╮ Line 7 │ │ Line 8 │ │ Line 9 ───╯ │ Line 10 ──╮ │ Original view Line 11 │ │ Line 12 │ │ Line 13 ──┼──╯ Line 14 │ View after <CTRL>d Line 15 │ Line 16 │ Line 17 ──╯ Line 18

If you find you only wish to scroll a few lines up or down, try

Remember these two actions by noticing e is close to d on a QWERTY keyboard corresponding to scrolling the view downwards, while y is located close to u, corresponding to an upward scroll.

To jump by paragraph, use { and }, corresponding to jumping a paragraph backwards and jumping a paragraph forwards.

Lastly, if you wish to go to a specific line, simply enter command mode and type the line you wish to reach. For instance, if you wish the cursor to jump to line 100, simply type :100<ENTER>.

Putting things together

After these separate introduction to commands and motions making up a "vim keybind", it's helpful to see a couple useful examples.

Additional Keybinds

There are a few extra useful keybinds that are on its own, introduced here.

Even though <Command> doesn't apply to most of the special keybinds listed here, <Count> does apply and you may repeat them with a number specified.

Basic Commands

Don't confuse the "Command" in this section title with command in Vim keybinds in the previous section. Command in this context refers to the commands issued directly to the editor through command mode.

Commands can be split into two major categories. Those that begin with a capital letter are user-defined or provided by a third-party plugin -- these commands don't ship with Neovim out of the box.

Commands described here will include the prepending :, which will switch the mode of the editor from Normal to Command. To run each command, press enter after each command is entered.

In this section, we'll introduce a few basic commands. More commands dealing with other features of the editor will be introduced in the next article in this series.

To force execute a command and ignore Neovim's attempt at stopping you, add ! after the command (! is read as "bang").

For instance, to forcefully write to a read-only file, :w! will usually suffice. As another example, to forcefully quit the editor without saving the changes, use :q! or :qa!.

Now, you should be able to perform basic editing tasks with Neovim. Next, we'll learn about Neovim's builtin features, such as the file explorer, global undo history, and how to add and move panes around; as well, we'll start to configure the editor by customizing its behavior and appearance.