What You’ll Learn

What You’ll Need

Note: If you have access to a VM, server, or local system with Vim installed and don’t wish to use the container, you can safely skip this step. It is preferential to use other systems; however, this container is provided for those who do not have access to any of the above systems. You will need to have Docker installed on your local machine to use this container. Typically, this will be for Windows users, without WSL or WSL2 installed with a Linux VM. (Docker Desktop for Windows can run in either WSL2 or Hyper-V mode.)

To use the container included with this tutorial, you’ll need to download the following files:

  1. Create a directory to hold the above files:
mkdir ciscou-vim-container/
cd ciscou-vim-container/
  1. Download the files and place them in this directory.
  2. Execute the build script; this will pull a Debian Linux container and install Vim within the container:
.\container-build.ps1

Note: By default, user-generated PowerShell scripts are not allowed to be run on Windows systems. You can change this either by opening up a PowerShell window with Administrator access (right-click, followed by Run as administrator) and running Set-ExecutionPolicy -ExecutionPolicy Bypass, or you can execute the script by copying the commands from the script and pasting them into a PowerShell window. (You can use the Windows command type to display the contents of a text file.)

script bypass

  1. Once the container is built, you will need to execute the run script that will run the newly built container. This will place you into an interactive Bash shell at the home of the root user.
.\container-run.ps1
  1. Once at the shell, to exit the container, use the keyboard combination <CTRL-P><CTRL-Q> (one key after the other, not simultaneously). This will return you to the Windows prompt.
  2. To stop the container, use the container-stop script (.\container-stop.ps1), or paste the command contained within to the Windows shell after exiting the container’s Bash shell.
  3. To restart the container, use the restart script (.\container-restart.ps1).
  4. Once the container is restarted, use the container-exec script to drop back into the container shell (.\container-exec.ps1).

Note: Each of the above scripts is just a single Docker command to speed up the adoption and use of the container. Once you become familiar with Docker and these commands, you may not need to use these scripts at all. Each of them can also be opened with a plaintext editor, such as Notepad++, VS Code, or even Notepad, to view and edit the contents in a GUI.

Once the container is up and running, you can move on to the remaining steps. There is no need to exit the container shell until you complete the rest of the tutorial.

vim-windows-lifecycle

After working with Vim for a bit, eventually, you’ll come across the need to move some text around within a file (or between files, but more on that later). Generally, within our OS or GUI text editors, we’ll invoke the CTRL- or CMD- set of commands (for example, CTRL/CMD-C to copy, CTRL/CMD-V to paste) to perform these actions. However, Vim, unlike other editors, doesn’t necessarily use the “modifier” keys to perform actions but depends on the operating mode (“normal”) and the correct letter keys being pressed:

Using (y)ank and (d)elete

Like (almost) every other Vim command, the y and d commands can operate with numerical arguments preceding the command (for example, 4y, 8d) or used to the end of a line or until a character has been matched (for example, y$ or dt=, where = is the character that you want to cut the text to). When either command is invoked, the text that has either been yanked or cut will be added to the “unnamed” register, which can be thought of in a similar way to an OS clipboard; it will be overwritten with the next yank or delete action. However, Vim includes additional registers to ensure that multiple actions can be performed before a “put” without losing text.

If text has been yanked, it will be placed in a special location, known as the “0” register, as well as the “unnamed” register (assuming the yank was the most recent action). If the most current action was a delete, that text will exist in the “unnamed” buffer, but will also be placed in the “1” buffer. Vim provides additional registers (“2” through “9”), but they are only used for additional delete actions. As you delete text from your file, the most recently deleted text will be placed in the “1” register, with the text that was in “1” being moved to “2.” This allows for multiple deleted sections of the file to be recovered in case you accidentally delete too much text. However, these registers are for deleted text only; yanked text will only exist in the “0” register, and if an additional yank action is performed, the text in “0” will be overwritten. This may seem odd, but because deleted text cannot be recovered from the file, while yanked text is just a “copy,” it follows that there should be more opportunities for deleted text to be recovered.

Current registers can be viewed at any time in the window by entering “normal” mode, then typing :register (or :reg for short). The “unnamed” register is indicated by "", while the numbered registers are indicated by their respective numbers. Additional registers are given below, but they are read-only and are not used for storing text.

(p)utting Text Back Where You Need It

So now that text has been added to various registers, we can put it back on the screen, regardless of which register it resides in. By default, p will paste the text on the “unnamed” register after your cursor location, while P will paste the text in “unnamed” before your cursor’s position. If you want to paste text from a specific register, you can use the " modifier, followed by the register number, then the p or P command. For example, to paste text from the “0” register, you would type "0p or "0P. If you want to paste text from the “1” register, you would type "1p or "1P. This allows you to have a workflow in which you can both yank and delete text while ensuring that you can place it as you wish within a file.

Note: You can also use the " modifier with the y and d commands to yank or delete text to a specific register. For example, to yank text to the “1” register, you would type "1y or "1yy. To delete text to the “2” register, you would type "2d or "2dd.

It is highly recommended that you explore these functions using a file with many lines of text. Utilities exist online to generate them (or you can copy and paste your favorite article to a plaintext file), or you can use the included long paragraph file to explore moving text around within the file.

yank-delete-put-registers

Note: In this animation, paragraphs are being yanked or deleted by the y} or d} commands, which yank from the current cursor position to the end of the paragraph. These are useful commands to know, but they are not required for this tutorial.

“Undo"ing the Commands

As you are working with text, you may run into a situation in which you have deleted too much (or the wrong section) of text, or maybe put some text in the wrong spot (or hit p when you needed P). Vim provides a way to undo these actions, using the u command. This command will undo the most recent action, whether it was a delete, paste, or other action. This command can be augmented using a numerical prefix (for example, 3u will undo the three most recent changes), and if you accidentally undo too much, you can use the CTRL-R key combination to “undo the undos” (redo) most recent action. Additionally, you can use the command :undolist to view the list of actions that have been performed and how long ago they were performed. This can be useful if you need to undo a specific action but have performed many actions since then.

There may be instances when using Vim in which the text that you wish to modify, delete, or copy doesn’t fall along neat boundaries. Other times, you may want to select multiple lines within a file to move them elsewhere. In these instances, it is helpful to use Vim’s visual modes to select the specific text required. These modes will present either character-level or line-level highlighting to the text, allowing you to easily select text for manipulation.

Note: There is a block-level visual mode as well. While block-level visual mode is useful when manipulating columns of aligned data (in CSV files, for example), it won’t be covered in this tutorial because its usage is drastically lower than the character and line-level visual modes.

Character Visual Mode

Character visual mode is very similar to the highlight function that exists within GUI editors. When operating in this mode, the text selected is incremented in character boundaries, allowing for very precise selection within a sentence or line. Additionally, when using character visual mode, standard keyboard level navigation keys are supported (w for word boundaries, 0 or $ for beginning and end of line boundaries, and so on), but arrow key navigation is supported as well. Once the desired text is selected, the standard (d)elete, (y)ank, and (c)hange are supported to manipulate the text. If text is deleted or yanked, it will be placed in the appropriate register to be put somewhere else within the file. To access visual mode, return to “normal” mode by pressing ESC, then hit the v key. You’ll see the editor indicate that you’re in visual mode at the bottom left of the editor. It is important that your cursor is at the start or end of the text that you wish to highlight, because any navigation from where visual mode is activated will cause that text to be highlighted for selection.

visual character mode

Line Visual Mode

Line visual mode operates in a similar way to character mode, but it only selects text along line boundaries. This is useful to copy or move large sections of text from within a file. In fact, it was used to move this section as it was originally placed after the discussion of buffers, windows, and tabs, but it made more sense to place it where it currently resides.

To enter visual line mode, ensure that you’re in “normal” mode, then use the SHIFT-v key combination. (The editor should display “visual line” at the bottom left of the window.) From there, simply use the arrow keys to move the cursor up or down the file, highlighting lines as it moves. When complete, invoke the desired action (yank, delete, change, and so on), which will affect the entire highlighted set of text. Much like visual character mode, ensure that your cursor is either at the start or end of the set of lines that you wish to select, because any navigation will highlight text.

Aside from moving blocks of text, another incredibly handy shortcut when working with multiple lines is being able to change the amount of indentation those lines have (say, for dealing with Python functions or indenting Ansible playbooks). Once the desired lines of text are selected, the > and < keys can be used to add or remove indentation.

visual line mode

Once you get the hang of using visual modes, along with the delete/yank/put key commands, you’ll quickly find that Vim can be just as fast and intuitive as any other GUI editor.

Aside from the fancy GUI interfaces and plug-ins, many modern text editors also provide an easy and intuitive way to work within multiple files at the same time, usually though the spawning of another tab somewhere within the editor interface. These tabs can then be selected using keyboard shortcuts or mouse clicks and allow a user to view and edit each file independently, as well as copy and paste text between the open tabs. Vim provides similar functionality, although the terminology is slightly different, using a combination of buffers, windows, and tabs.

What’s a Buffer?

Whenever a file is opened with Vim, the contents of that file are placed in a buffer for the edits to occur. This approach is similar to that of other editors. Every change made to a file is not immediately reflected in the contents on the disk of your computer; you have to use the “save” feature to ensure that what is on screen is written to storage. When you open a file with Vim, either from the command line or through the :edit [filename] command, the file is loaded to the current buffer in the full screen view of your terminal.

If you wish to edit multiple files, you can either use the :edit [filename] command from your opened Vim session, or you can invoke multiple filename arguments after the vim command within the command line, similar to:

$ vim file1.txt file2.txt file3.txt

Each of the opened files will be placed within their own buffer, with each buffer occupying the full screen view of that terminal window. With a default installation of Vim, the list of buffers will not be present on the screen; however, you can view which buffers exist by using the :buffers or :ls commands. You can move between buffers by using :buffer [n] (where [n] is the number from the list) or by using :bnext or :bprev. Buffers can be closed by using the :bdelete [n] command, where [n] is an optional argument for the buffer number. (If not present, it will close the current buffer.)

vim buffers

Windows in Vim? I Thought This was *nix…

A window is simply a view into a buffer; that’s why they’re called “windows.” At any time, a window can display only one buffer at a time. However, you can use windows to split your Vim session, allowing you to display multiple buffers simultaneously, similar to how GUI editors allow the editors view to be split. The biggest difference with Vim is that buffers and windows are not connected in any way; buffers opened in windows can have the containing window closed, but the buffer will still exist and be accessible. This allows windows to be completely ephemeral and able to be used at a point in time, rather than tied to the buffer to which they are contained.

Some common window commands within Vim are:

This list isn’t exhaustive, but it will provide a solid baseline for using Vim windows. One important note is that if performing multiple window splits, each split will only affect the currently selected window. In this way, if a window is split horizontally once, the cursor is moved to the bottom half, and then in a vertical split, a window similar to the following will result.

splitting the window

Tabs, and Not the Whitespace Kind

All of this leads us to tabs, which is just a view into one or more windows. When the create function is invoked, a new tab will be added to the top of the Vim editor. This new tab will have the single window present, with a currently empty buffer displayed. However, just like everything with Vim, tabs are detached from buffers, so if a file is previously opened as a buffer in the editor, the window in that new tab can display the previously opened buffer. Confusing, huh?

The advantage in using tabs is that the current windows file is displayed at the top of your editor next to the other inactive tabs. Also note in the following screenshot the number “3” in the first tab; this is the number of current windows within that tab.

vim tabs

Some common tab commands are:

Putting It All Together

The best way to learn how to use something new is by exploration. Create copies of the long paragraph file with unique filenames, and practice opening up the files in buffers. From there, practice splitting the current editor into multiple windows and move through which one is active, as well as shifting the active buffer within a window. Finally, close some windows and open up buffers as tabs, and practice navigation through the tabs. Once you develop the muscle memory, you’ll start realizing how much faster your editing can be without having to move your hands from the keyboard.

So far, we’ve discussed how to manage multiple files and snippets of text within Vim to make file editing similar to that of GUI-based editors. However, there is one important function that tools like VS Code, PyCharm, and others have—the ability to run a terminal alongside the editor (for example, testing code, gathering directory listings, or generating UUIDs). In today’s world, we can usually just open up another terminal window in a tab next to our Vim editor and call it a day. However, there are times when working in remote systems where it is more convenient to temporarily background the Vim process, or invoke a terminal in a tab, rather than create a new SSH session to the remote system.

Note: There are other ways to manage multiple sessions within a *nix-based system, including Screen and tmux. However, discussion of these utilities is beyond the scope of this tutorial.

Backgrounding the Process

Because Vim is executed like any other process in a POSIX-based operating system, it will obey standard process signals. In this way, we can use the universal process background key combination of CTRL-Z. (You must be in “normal” mode for this to work.) This will cause the Vim editor to be removed from the screen, and you will be returned to the terminal as it was before you launched Vim. You are able to run whichever commands are needed from the terminal as normal. When you wish to return to Vim to continue editing the file, type fg at the command line, and you will be returned to Vim with the cursor at the position you were when you backgrounded the process.

Launching a Terminal in Vim

Beginning with Vim version 8, it is possible to launch a terminal within Vim itself. You can do so using the :terminal command, which will create a new window within the Vim editor that contains a shell process. By default, this window will appear above your current file; that is, it will be on top, while the current file will be on the bottom. To change this, you can either invoke the :below terminal command, which will cause the window split to occur below the current file, or if you forget, you can always use the command CTRL-w x to swap window positions. To move between the terminal and file windows, the same window commands are used.

vim terminal in window

If you prefer to launch a terminal within a completely new tab, rather than a window, you can invoke :tab terminal, which will launch a separate tab containing the terminal process. You can flip between the tabs as you would if two files were open.

vim terminal in tab

Whether the terminal is launched in a tab or window, the terminal will be in “terminal-job” mode. This mode behaves the exact way that a normal terminal would; enter commands and press RETURN, and view the output. However, there may be times in which the terminal window needs to be in “terminal-normal” mode, perhaps to resize the height of the window, for instance. In “terminal-normal” mode, you can enter commands as if the window were in “normal” mode, and it is entered by using the key sequence CTRL-w N (capital on N; Vim is case-sensitive). Once all desired Vim-centric commands are entered, you can return to “terminal-job” mode by pressing i.

Congratulations! You’re well on your way to becoming a Vim expert!

Learn More