1. Introduction

The Vi editor is the default in many Linux environments. Because of this, we might often end up in Vi without requesting it explicitly, like when invoking visudo. Seeing a screen with information from a large file and not being able to navigate around it quickly and easily can be stressful.

In this tutorial, we’ll go over basic ways to navigate the █ cursor and viewport when editing a file in Vi. First, we discuss basic movement. After that, we delve into scrolling commands and their application.

For brevity, we use vi (Vi) when referencing both the Vi and Vim editors. Where they differ, the reader is free to add and remove m (M) if necessary. All methods we discuss are used in Normal (Command) mode.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments unless otherwise specified.

2. Basic Movement

Perhaps the simplest method of navigation in Vi involves the keyboard arrow and paging keys or the mouse. Arrows move the cursor while paging keys change the edit window, i.e., view.

However, we do have the option to use commands and key combinations, many of which involve Control.

2.1. Cursor Movement

There are two sets of keys that perform the main atomic cursor movements:

+------------------------------------------------+
| Arrow    | Key | Function                      |
|==========+=====+===============================|
| <Left>   | h   | move a character to the left  |
|----------+-----+-------------------------------|
| <Right>  | l   | move a character to the right |
|----------+-----+-------------------------------|
| <Up>     | k   | move a line up                |
|----------+-----+-------------------------------|
| <Down>   | j   | move a line down              |
|----------+-----+-------------------------------|
| <Return> | -   | move to start of lower line   |
+------------------------------------------------+

We can move the Vi cursor a single character horizontally via the Left or h and Right or l keys:

  • <- arrow, h: move a character to the left
  • -> arrow, l: move a character to the right

If we’re at the beginning of a line, or h would go to the end of the previous one, if any. Similarly, pressing or l at the end of a line jumps to the beginning of the next one.

On the other hand, we can move the cursor vertically via the Up or k and Down or j keys:

  • ^ arrow, k: move a character upward
  • v arrow, j: move a character downward
  • : move to the beginning of the next line

To move multiple rows or characters, we first type a number and finish with the relevant movement key.

Critically, if the current horizontal cursor position is further than the length of the line we’re jumping to, Vi places the cursor at the end of the line after the vertical move:

Line 1!
Line 2 is longer.█
Line 3.

So, pressing Up or k in this scenario would place █ after the exclamation point. On the other hand, pressing Right or l goes to the beginning of Line 3.

In the same way, if we try to move the cursor outside the current edit window, both will shift accordingly. Still, sometimes we just want to move the view without changing the cursor position.

2.2. Page Movement

Similarly, we have several ways to move the edit window:

+--------------------------------------------------+
| Key        | Combination | Function              |
|============+=============+=======================|
| -          | Ctrl+Y      | move a line up        |
|------------+-------------+-----------------------|
| -          | Ctrl+E      | move a line down      |
|------------+-------------+-----------------------|
| <PageUp>   | -           | move a page up        |
|------------+-------------+-----------------------|
| <PageDown> | -           | move a page down      |
|------------+-------------+-----------------------|
| -          | Ctrl+U      | move a half page up   |
|------------+-------------+-----------------------|
| -          | Ctrl+D      | move a half page down |
+--------------------------------------------------+

So, we can employ combinations or the and keys to move a whole page or half a page:

  • : move a page up
  • : move a page down
  • Ctrl+U: move a half page up
  • Ctrl+D: move a half page down

The cursor will be placed on the last row after an upward move and on the first – after a downward move. Exceptions are the edge pages.

In addition, we can just move the edit window a single line:

  • Ctrl+Y: move a line up
  • Ctrl+E: move a line down

In this case, the cursor doesn’t move unless it’s about to go out of the edit window.

2.3. Mouse Navigation

Naturally, if mouse support is enabled and available, moving the mouse changes the potential cursor position, while clicking sets the actual cursor position.

Although this may be the more human-friendly manner of navigating the cursor around the current edit window, switching views isn’t usually as easy. Even mouse wheel scrolling can be too inaccurate.

3. Scrolling Commands

For more refined scrolling, we can avoid keys, key combinations, or the mouse and instead use scroll commands.

These again move the cursor only when necessary, e.g., at the content edge.

3.1. Scroll Off Options

To begin with, there are two important options that affect scrolling:

  • scrolloff (so): how many lines to ensure exist above and below the cursor at any given time (default 0)
  • sidescrolloff (siso): how many columns or characters to ensure surround the cursor from both sides at any given time (default 0)

Thus, the default value of 0 means there are no context restrictions. However, setting high values for scrolloff or sidescrolloff would mean the cursor might be unable to move away from the middle of the screen in both directions, except when we reach the edge of the content.

Keeping this in mind, let’s continue with actual commands for scrolling.

3.2. Vertical Edit Window Move Relative to Cursor

Several commands are responsible for aligning the edit window relative to the cursor:

+------------------------------------------------------------+
| Command   | Function                                       |
|===========+================================================|
| zt        | reposition edit window, current line at top    |
| z<Return> | ^ and move to first non-empty column           |
|-----------+------------------------------------------------|
| zz        | reposition edit window, current line at center |
| z.        | ^ and move to first non-empty column           |
|-----------+------------------------------------------------|
| zb        | reposition edit window, current line at bottom |
| z-        | ^ and move to first non-empty column           |
+------------------------------------------------------------+

Prepending a line number to any of these commands places the cursor on the respective line and moves the edit window so the line is at the respective location relative to it.

There are two important caveats:

  • z: inserting a number between z and may shrink the edit window permanently
  • zz: using zz with CapsLock on results in the ZZ command, which saves the buffer and exits the editor

For example, let’s consider this small Vi window with five lines:

Line 11.
Line 12.
Line 13.
Line 14█
Line 15.

We assume a buffer with Line # on each line between 1-50.

So, zt makes Line 14. go to the top:

Line 14█
Line 15.
Line 16.
Line 17.
Line 18.

From this position, z- relocates the edit window, so Line 14. is at the bottom:

Line 10.
Line 11.
Line 12.
Line 13.
Line 14█

In the latter case, if there was whitespace under the cursor, it would also be moved to the next non-whitespace character.

3.3. Horizontal Edit Window Move Relative to Cursor

With wrapping off, we can also scroll horizontally:

+-------------------------------------------------------------+
| Command  | Function                                         |
|==========+==================================================|
| ze       | move view left, cursor to far right              |
| zs       | move view right, cursor to far left              |
|----------+--------------------------------------------------|
| z<Left>  | move view a character left, see more on right    |
| zh       |                                                  |
|----------+--------------------------------------------------|
| z<Right> | move view a character right, see more on left    |
| zl       |                                                  |
|----------+--------------------------------------------------|
| zH       | move view a half page left, see more on right    |
|----------+--------------------------------------------------|
| zL       | move view a half page right, see more on left    |
+-------------------------------------------------------------+

These options are especially useful when dealing with long lines of code. In addition, we can refine the above with the commands to move the cursor horizontally according to the characters on the line.

On the other hand, we also have search-based methods to position the cursor anywhere in the buffer.

4. Summary

In this article, we talk about positioning the cursor and view in the Vi editor.

In conclusion, depending on our situation, we have multiple options to make our navigation and edit window operations in Vi more convenient.