Vi

I'm a huge fan of Vi. Maybe you've never heard of it. Maybe you've never used it. This page won't teach the basics, as those have been covered better in the following places:

The history of Vi

ed

In 1967, while studying at the University of California, Berkeley, Butler Lampson and Peter Deutsch built the "quick (text) editor" qed, for the Berkeley Timesharing System.

In 1969, just two years later, Ken Thompson, who was familiar with qed, wrote the text editor ed, one of the first three components of the UNIX operating system.

Given the limitations at the time, ed has become infamous for its notoriety as a rather hostile interface. Its terse communication is best captured by the warning message it presented when users were about to quit the program without saving any of their changes made to the document: ?

ex

In 1976, Bill Joy wrote ex, which added features that took advantage of video terminals. Bill Joy had been inspired to improve on ed after visiting a friend in London who had himself created a similar, less performant extension of ed. ex derives its name from its origins as an extended version of ed.

In 1979, Bill Joy's improvements to ex had become quite comprehensive. It now featured, in addition to its line editor mode, a fully visual editor mode. Users were now able to see the text that they were editing. This improvement was so dramatic that it eclipsed the utility of ex's line editor mode, prompting the name of the command to be changed to vi, as we know it today.

In 1991, a number of improvements upon the original vi were released. The developers named this program vim, or "Vi improved." Some of the most notable features released in this edition include autocompletion, spell-check, diff comparison, file-merging, code-folding, and regular expressions.

Getting Started

The original Vim package has grown to include everything but the kitchen sink. You'll find the amount of files and dependencies it adds to be rather excessive, as it will force the installation of numerous massive dependencies, along with many features you likely don't need. For this reason, many developers have begun working on Neovim, which is more in line with the original spirit of the Vim package. For this Wiki entry, I will be assuming that you are using Neovim, but most of these commands should work in regular Vim as well. In either case, I'll be referring to the program as "Vi," the original program.

Vi has a tutor mode, which can be accessed by typing $ vimtutor Check out syntax examples

vim Key Notation

For more help, inside vim type :help key-notation

Note that there are 32 control characters, which vim has bound to specific key-combos. For instance, < C-a > means ⌃ A. At the time, there wasn't enough room to support any control+shift+char type combos, so < C-a > is the same thing as < C-A >

Notation Meaning Hotkey
< BS > ⌫ backspace ⌃ H
< Tab > tab ⌃ I
< Esc > ⎋ escape ⌃ [
< CR > ↩ return ⌃ M

Moving Around

By Character

Key Function
H ← 1 character
J ↓ 1 character
K ↑ 1 character
L → 1 character

By Word

Key Function
W → to next word
E → to word ending
B ← back to word beginning

The Meta Key

Vi often refers to the option key () and the alt key () as the meta key, and will use <M-x> as the notation to denote pressing ⌥ X. This is mangling the meaning of the meta key a bit. Since most keyboards didn't have a meta key, Vi follows Emacs, and uses escape followed by a key as if they pressed a meta key. The meaning of the meta key has changed over time, and has had different, if not contradictory meanings. In JavaScript, the DOM treats the command () and windows () as the meta key.

Basic Launch Commands

3 Modes in Vim

Normal/Command Mode

This is the place to give the editor commands and make changes.

Insert Mode

Cmdline Mode

Useful Commands

Selection Mode

ex Mode

The history of ex

In the mid 1970s, GNU's file editor, ed needed some extensions. Instead of updating ed itself, Bill Joy developed an extended mode ex as well as a visual mode vi

ex is a file editor, which makes it different than the GNU's stream editor sed, which was built by Lee McMahon in the early 1970s. The advantage of ex is its ability to provide more functionality than what's found in sed and awk. For instance, ex has the ability to handle very complex chains of tasks. ex has support for matching statements that span across several lines.

ex Mode

If you're inside vim you can enter ex mode by typing : in command mode. You will automatically exit ex mode by submitting the command or deleting the text on the line.

ex Commands

ex is an extension of its parent ed and supports a very similar syntax to ed and sed. Unlike ed and sed however, ex is more powerful. For instance, it supports regular expressions that span multiple lines of a file.

Range Selection

The first thing to specify to ex is the range. Some characters have a special meaning when specifying the range of lines to search.

  1. num specifies to search just line num itself
(Select just line 5)
:5
  1. a,b specifies lines a through b inclusive

    (Select lines 2 through 4)
    :2,4
    
  2. $ specifies the last line

    (Select all lines from 10 and below)
    :10,$
    
  3. % specifies all lines (equivalent to 1,$)

    (Select all lines)
    :%
    
  4. . specifies the current line

    (Select all lines before the current line)
    :1,.
    
  5. + specifies the next line(s)

    (Select the next 10 lines, including the current line)
    :.,.+10
    
  6. - specifies the previous line(s)

    (Select the previous 10 lines, including the current line)
    :.-10,.
    
  7. /regex specifies the next line containing the RegEx regex

    (Select the first line containing `example` after the cursor current position
    :/example
    
  8. ?example specifies the previous line containing the Regex example

    (Select the first line containing `example` before the cursor's current position
    :?example
    

Command Selection

Chaining Commands

You can use the | character to chain multiple ex commands together.

(Swap every "old" with "new" and prepend a # to every line)
:% s/old/new/ge|i#

Launching ex

You have multiple ways of calling ex

# Run ex on file.txt
ex file.txt
# Run ex on file.txt
vim -e file.txt

Calling ex from the command line

If you've ever used vim or its parent vi you've probably used ex without even knowing it. Any command that starts with : is actually an ex command, it's specified inside of vi but it's executed with ex and mapped to the current file.

ex commands can be run without even entering a file. To do this, you can take advantage of the command line features that ex has implemented.

Understanding ~/.vimrc

Your ~/.vimrc file is a file that contains Vimscript code. It automatically runs the code in this file every time Vim is launched.

It's good to write as many comments as possible, as you'll one day forget what is in your ~/.vimrc file

Variables

Internal-Variables

When you see something like g:onedark_termcolors:256 in your ~/.vimrc it's referring to an internal variable.

Fun fact, not sure where to put it: The "rc" in ~/.vimrc stands for run commands

You can always check :help internal-variables to review the types of internal-variables but here are the most common ones.

| buffer-variable | b: | Local to the current buffer | | | | window-variable | w: | Local to the current window | | | | tabpage-variable | t: | Local to the current tab page | | | | global-variable | g: | Global | | | | local-variable | l: | Local to a function | | | | script-variable | s: | Local to a | :source | 'ed Vim script | | function-argument | a: | Function argument (only inside a function) | | | | vim-variable | v: | Global, predefined by Vim | | |

Examples

Basic Functions

Special Characters

:r filename.txt will read the specified file into the buffer :r !ls will read the files in the current working directory into the buffer :! will run the last external command in your bash history :!! will repeat the last command you executed :silent !echo "Hello" will not ask for the user to press enter to confirm the change

Enabling syntax highlighting in code-blocks

If you'd like your code-blocks inside markdown to support syntax highlighting, go into your ./vimrc file and add the following line

" Enable highlighting for html, ruby, python, and bash "
let g:markdown_fenced_languages = ['html', 'ruby', 'python', 'bash=sh']
" Allow syntax highlighting for code blocks of up to 100 lines (Default is 50) "
let g:markdown_minlines = 100

Help

You can get help in vim by typing :help topicname

Usually this opens in a small window, so you can type ⌃ W T which open the current buffer in its own tab.

An alternative option is to have the help page open in its own full-screen tab, which you can do with the substitution below

" Old method "
help grep
" New method "
tab help grep

Tab navigation (normal mode)

Key Mappings

You can specify which mode you would like to transform the operation of a given key combination.

Non-Recursive Mappings

The following mapping combination results in pressing d in insert mode outputting wat because the keystroke transformations execute recursively.

imap d D
imap D wat

d D wat

For this reason, it's good to also have non-recursive mappings.

Regular Expressions

The syntax for vim regular expressions is slightly different than those used in POSIX regular expressions, the ones that are used by applications like grep and sed

Metacharacters

Edit File Remotely

You can use vim to edit files hosted remotely on a different computer. First, however, you'll need to add your public SSH key to the ~/.ssh/authorized_keys file on the host of that computer

vim scp://user@remote.network/Documents/file.txt

Save & Quit

In ex mode:

In Normal mode:

Confirmation Prompt

If you'd rather not have an error thrown at you when you're trying to exit a file, you can have vim ask you if you'd like to save your changes when you try to quit from a file. Just add set confirm to your .vimrc file.

Changing Directories With ex Mode

:cd

The :pwd command prints the present working directory

Custom ex commands

You can add these to your .vimrc to add custom ex commands.

User Defined Commands

User defined commands uses the command keyword, and has the following syntax

:command WriteAndQuit wq

This will allow you to type :WriteAndQuit as an ex command and substitute :wq in its place.

Override Existing Commands

Overriding pre-defined commands uses the :ca keyword (command abbreviate), and has the following syntax

Now when we use the :w command it will be replaced with the :up (update) command. This is a good idea, because when you use the :w command, you are writing the current buffer even if there are no changes, which sets the file as modified.

However, there's a problem. If :up was modified, we would want it to preserve its original meaning. To do this, we'll disable remaps for the right hand side argument, with the cnorea (command no remap abbreviate) keyword.

:cnorea w up

Editing Text Commands

Usually it's referred to as copy, cut, and paste, but in the interest of having the verb match the keybindings, the translation is as follows for vim

Move Lines in ex Mode

No need to cut a group of lines and then paste it somewhere else, you can use the :m[ove] command to send a range of lines to be below the specified line.

:3,8m 23

Copy Lines in ex Mode

You have some choices, you can use :t or :co[py], which will paste the range of lines below the specified line.

:3,8t 23

Telling vim about the filetype

If you want to enable syntax highlighting but you're in a file without a file extension, you can use the :set command to modify the ft value, and tell vim what file to treat it as.

:set ft=sh

Using the shell without leaving vim

:sh

And just press when you're done to return to vim

Managing Viewports

If you open a help page, it opens a viewport in the top vertical half of the screen. This is a good time to learn the commands for managing multiple viewports, as it's often useful to be working on multiple documents at once.

The typical syntax for managing a viewport in normal mode is ⌃ W . Luckily you don't have to let go of the key when you press the second key, as vim binds both <C-w>o and <C-w><C-o> to the same function by default.

To see all of the bindings, type :tab h index

Focusing Windows

Shortcut Function
⌃ w h Focus on the window to the left
⌃ w j Focus on the window below
⌃ w k Focus on the window above
⌃ w l Focus on the window to the right
⌃ w w Focus on the next window (wraps around)

Moving Windows

Shortcut Function
⌃ w H Move active window to the left
⌃ w J Move active window to the bottom
⌃ w K Move active window to the top
⌃ w L Move active window to the right

Opening/Closing Windows

KKy sequence Action performed Equivalent ex command
⌃ w s Horizontally split the current window :sp
⌃ w v Vertically split the current window :vsp
⌃ w q Quit the active window :q[uit]
⌃ w c Close the active window :clo[se]
⌃ w o Close all other viewports, making this viewport full-screen :only
Shortcut Function ex Command
gt Go to the next tab :tabn[ext]
3gt Go to the 3rd tab :tabn3
gT Go to the previous tab :tabp[revious]
1gt Go to the first tab :tabn1
N/A Go to the last tab :tabl[last]

Opening/Closing Tabs

|⌃ w T|Open active window in its own tab| |⌃ w c|Close the current tab|:tabc[lose]| |N/A|Close all other tabs|:tabo[nly]|

Registers

Read-Only Registers

Special Registers

Registers in Insert Mode

When you're in insert mode, you can press <C-r>, followed by a register name, to insert the contents of that register

Registers in Command Mode

Copying to Clipboard

  1. Normal Mode

Use the " mapping to refer to the clipboard register "+

  1. Command-line Mode

Use the :y[ank] comamnd

Writing to registers

The @/ register stores the last search pattern

vimdiff

On your terminal, the vim command has a -d flag which you can use to activate vim's diff mode.

Filepath Shortcuts

To test any of these out, you can type echo expand('%:p')

expand() Selectors

As we saw above with echo expand('%:p'), we can do the same with some expand() selectors

" :help :<cword>

" the [c]ursor [word] in its current position
echo expand('<cword>')

" the [c]ursor [WORD] in its current position
echo expand('<cWORD>')

" for autocommands, the filename of the buffer being manipulated
echo expand('<afile>')

Splitting the filepath can be done by appending :h or :t as follows:

Motions (Text Objects)

In vim, motions, otherwise known as text objects can be used to execute a modification in a way more specific than anything possible using just the mouse. They follow the following structure:

<number> <command> <motion>

For instance, 3dk will delete the current line, and the 3 lines above it. Vim intelligently infers the context from within the motion, allowing for the following types of command-chaining.

Here are some additional examples:

(The following apply if you've added vim-surround to your packages.

Searching

If you've searched for a word, perhaps /pattern then you can use some familiar motions to move around, as shown below:

Marking

Sequence Command Executed
ma set mark "a" at current cursor location
m' set the previous context mark line
m` set the previous context mark
'a jump to the line of mark a
`a jump to line & column of mark a
d'a delete from current line to mark a
c'a change text from current line to line of mark a
]' jump to next marked line
[' jump to previous marked line
]` jump to next lowercase mark
[` jump to previous lowercase mark
'' jump back to previous line
`` jump back to previous line & column
`[ jump to start of last change/yank
`] jump to end of last change/yank
`< jump to start of last visual area
`> jump to end of last visual area
`. jump to where the last change was made
`^ jump to where insert mode was last stopped

Yanking

Special Insert Mode

Command Substitution

" if you try this command, you'll get an error
source fnamemodify(stdpath('config'), ':h') . '/vim' . '/config.vim'
" E484: Can't open file fnamemodify(stdpath('config'), ':h') . '/vim' . '/config.vim'

" if you try this command, it will work
source `=fnamemodify(stdpath('config'), ':h') . '/vim' . '/config.vim'`
" Sourcing /Users/tommy/.config/vim/config.vim

netrw

The netrw tool, (which stands for Network Read/Write) within vim is a useful way to quickly navigate across folders in your terminal. The standard workflow of constantly typing cd and ls is far from ideal. Being able to successfully navigate through your filesystem using netrw will allow you to develop software with expediency.

Moving Files

Creation/Deletion

String Manipulation

let &runtimepath .= ','.join(split(expand($XDG_CONFIG_HOME ."/vim{,/after}"),'\n'), ',')
" (the stdpath() function only exists in `nvim`)
let s:dotfiles = fnamemodify(stdpath('config'), ':h')
echo s:dotfiles
" => '/Users/austin/dot'

Custom Functions & Commands

I wrote this function because I thought it wasn't built in natively, but it serves as a useful example of how to declare a function and how to declare a command.

" Function to open a wiki page for note-taking
" :help function()
function Jot(entry)
    let entry = glob('~/wiki/content/posts/' . entry)
    " Add the suffix if it hasn't yet been added
    if entry !~ "\.md"
        entry += "\.md"
    endif
    tabedit entry
endfunction

" :help command-nargs
" :help q-args
" Create a command (with tab completion) for opening wiki posts
command -nargs=1 -complete=file_in_path Jot call Jotf(<q-args>)

Quick Note on &path and :find

In the future, if you want to be able to easily edit a file in the future, you can add the directory that it list within to the &path variable. From there, you can simply type :fin[d] file.

Once that command is received, Vim will check each directory specified in &path, and find a match to file or a file that matches file and has a suffix specified by &suffixadd. If it finds a match, it will open that file for editing in a new buffer. If you'd like it to open in a new tab, you can use :tabf[ind] instead.

For Loop

for number in [1, 2, 3, 4]
    echo number
endfor

Help Tags

To open up the right help page for your package, sometimes you need to generate the helptags, as this isn't usually done automatically when you clone the package. To do that, run the following command

" Generate helptags for all help files in the runtime
:helptags ALL

Pattern Searching

Useful Window Keybindings

Each of these commands is preceded by \C-w, or alternatively, the :wincmd command

Hotkey Effect
n open a new window (below), open empty
v vertical split window
s horizontal split window
p go to preview window
z close preview window
R rotate window vertically
r rotate window downwards
r rotate window upwards
w cycle through windows
p go to last accessed window

Useful Pending Search Keybindings

Hotkey Effect
Ctrl-g Move cursor to next match
Ctrl-t Move cursor to prev match

Netrw

Hotkey Effect
mz compress/decompress file
Hotkey Effect
gh Start select mode
gv Reselect previous visual block
gn Search forward for last used search pattern
gN Search forward for previous used search pattern
dgn Delete the next match to the search pattern
o Go diagonally across selection area
O Go to other side of the current row's selection
d Delete highlighted
c Change highlightred

Random Cool Keybindings

Hotkey Effect
z= Suggest spelling for word
@: Repeat last ex command
ga Print the UTF-8 character code for the character under the cursor
:= Print the last line number
+ Move down to the first non-whitespace character in the row below

Knowing Where to Look For Help

Useful Command Flags when Opening Vim

All the characters that you type are recorded in the file "scriptout", until you exit Vim. This is useful if you want to create a script file to be used with vim -s or :source!.

# -h -w
# -h :complex-repeat

# Append normal mode input to the file `inputs.vim`
vim -w 'inputs.vim' file.txt

# Overwrite `inputs.vim`
vim -W 'inputs.vim' file.txt
vim -s 'inputs.vim'

Useful Help Pages

Jump Motions

Useful to check out :help jump-motions

Quickly Open Help

Setting Keybindings

Completion

Substitution

Examples of the :s[ubstitute] command:

Examples of the substitute(expression, pattern, replacement, flags) command:

Replacement Expessions

You can use \= in a :substitute command to signify that you'd like to replace matches to the pattern with an expression instead of a string. To learn more, visit :help sub-replace-expression

Abandoning a git commit

Vi will exit with an error code, which aborts the pending commit entirely.

Clearing Current File

Setting the File Name

View Wordcount

Go to a particular line

I'm surprised I went so long without discovering this on accident.

NUMBER<CR>