Introduction to Vim
This post briefly outlines what vim is built of. It is based on superb vim manual and various articles I found about it on the internet. I listed them for reference at the bottom. Beyond that, I also prepared a snipptes you can execute to get your feet wet and see how it works in practice.
It’s an introduction to a series of posts where I will dive deeper into its capabilities.
Without further ado, let’s go.
vim stands for Vi IMproved. It’s a FOSS text editor introduced to public on November 3, 1991 by Bram Moolenaar. Initially developed as a vi port for Amiga, but after its public release in Fish Disk #591 (Vim 1.14, 1991) it gained popularity and was soon ported to other platforms. For a short period (1991-1994) it used to be called Vi IMitation, but it changed to Vi IMproved on August 16, 1994 with introduction of Vim 3.0. Bram briefly mentioned reasoning behind it in the manual:
*[…] there are so many improvements that a name change was appropriate.
Even though Vim is over 30 years old, it’s still actively developed, and used worldwide.
How to install vim
To install Vim, do a search for precompiled binary for your platform/OS, or compile from source: https://github.com/vim/vim?tab=readme-ov-file#compiling
vim vs gvim
Besides vim, you might also encounter gvim. This is just a vim with GTK/X support for GUI.
Key concepts
Vim introduces a few conventions that it’s good to be aware of to get most out of it, and not get lost. Starting out with display, the text is loaded into buffers, then displayed in windows, and sometimes tabs.
Buffers, windows, and tabs
A buffer is the in-memory text of a file.
A window is a viewport on a buffer.
A tab page is a collection of windows.
Buffers
Buffers can be:
- active - file was loaded (if it exists), buffer is displayed in a window,
- hidden - file was loaded (if it exists), buffer is not displayed in a window,
- inactive - file not loaded, nor displayed in a window.
Buffer contents might differ from the source file, when it was edited in vim, until it’s written.
Buffers are uniquely identified by numbers (bufnr) that don’t change over a session lifetime.
To list all buffers execute :buffers.
:echo bufname('%') and :echo bufnr('%') can be used to get name and number of a currently active buffer.
Windows
Main window can hold several split windows.
Windows are uniquely identified by window IDs that don’t change over a session lifetime. What in turn change are window numbers, when windows are opened or closed. Windows are numbered from top-left to bottom-right, so any changes to it’s layout, i.e opening new file, or closing it, causes window numbers to recalculate to reflect that.
The window number is only valid in one specific tab. The window ID is valid across tabs. For most functions that take a window ID or a window number, the window number only applies to the current tab, while the window ID can refer to a window in any tab.
Vim starts with one window by default, unless you pass -o , -oN, -O, or -ON flag.
The case of -o parameter determines whether windows are opened horizontally (-o), or vertically (-O). There is a variation with N number suffix that tells exactly how many windows to open. When N is smaller than number of input files, then some of those files (the last ones) don’t get a window. When no files are passed in this variant, N windows with empty buffers are opened instead.
To visualize this:
vim -o file1 file2 file3opens three files in three horizontal windows,vim -O file1 file2 file3opens three files in three vertical windows,vim -o2 file1 file2 file3opens two files in two horizontal windows, no window is provided forfile3, and its buffer isinactive,vim -O1 file1 file2 file3opens one file in vertical window, no windows are provided forfile2, andfile3, and their buffers areinactive,vim -o3opens three horizontal windows with empty buffers,vim -O3opens three vertical windows with empty buffers.
Tabs
Each tab can hold multiple windows.
Tabs can be opened by prefixing a command with a tab keyword, i.e:
:tab help
or by using :tabnew <filename> , that othat opens tab with a file contents, if it exists, or empty buffer otherwise. You can skip <filename> altogether to create a new tab with empty buffer.
Tabs can be closed with ZZ.
Todo: navigate between tabs, rearrange tabs
Having displaying capabilities covered, let’s move to a text editing capabilities. Compared to other text editors, where you just get interface to type text, there are multiple operational modes that influence how vim behaves, and what it lets you to do. Sometimes their behavior is not so obvious, which in turn leads to confusion, especially when you are just starting to learn it.
Modes
https://vimhelp.org/intro.txt.html#vim-modes
There are seven basic modes, and seven additional modes.
Basic modes are:
- NORMAL
- VISUAL
- SELECT
- INSERT
- COMMAND
- EX
- TERMINAL-JOB
Additional modes are out of scope of this article and will be covered in a separate post.
Modes lets you input text, command, do a visual selection, or replace text.
Then, we have motions that lets you navigate and select text in a smart ways.
Motions
In other words, how you navigate over text. This cheatsheet cover it nicely.
Following are marcos, that lets you record set of keystrokes, and replay it with a single keystroke on a different part of the buffer. This comes handy for automation of tedious and repeatable work, like renaming enums.
Macros
There is also a dedicated scripting language available that you can use to extend vim in plugins or .vimrc
Automatic commands
Automatic commands (also known as auto commands, autocmd) are commands that are executed automatically when given event occurs. I like to think about them as event listeners, where commands are listener callbacks that are executed when event happens.
The complete list of events you can listen to is here.
There are plenty of them to tweak, and manual warns against its powers, as it can destroy your text if not used wisely.
Commands can be grouped, and its execution scope can be narrowed down to a file pattern.
This autocmd echoes test each time json file is read:
augroup TestOnOpen
autocmd BufReadPost *.json echo "test"
augroup END
You can remove autocmd by suffixing the keyword with exclamation mark:
augroup TestOnOpen
autocmd! BufReadPost *.json
augroup END
Bibliography
- https://vimhelp.org/
- https://arstechnica.com/information-technology/2011/11/two-decades-of-productivity-vims-20th-anniversary/
- https://moolenaar.net/vimstory.pdf
- https://www.free-soft.org/FSM/english/issue01/vim.html
- https://invisible-island.net/vile/vile.faq.html
- https://www.free-soft.org/FSM/english/issue01/vim.html