Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
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.
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.
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:
If we’re at the beginning of a line, <Left> or h would go to the end of the previous one, if any. Similarly, pressing <Right> 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:
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.
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 <PageUp> and <PageDown> keys to move a whole page or half a page:
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:
In this case, the cursor doesn’t move unless it’s about to go out of the edit window.
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.
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.
To begin with, there are two important options that affect scrolling:
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.
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:
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.
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.
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.