Vi

The best editor around

Wednesday, Jun 17, 2020

Vim

These two programs were written in C during the mid 1970s and were eventually merged together. Today, ex has gone on to become an integral extension of vi's functionality.

vim's most notable features

As of version 8.0, vim notably supports

Getting Started

The original Vim package has grown to include everything and 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 several different programming languages, 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.

Learning vim

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

vim Key Notation

For more help, inside vim type :h 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

In vim, the alt key is often referred to as the meta key.

Notation: < M - x > is the same as ⌥ X

Warning: If you’re using MacOS, make sure your terminal has the setting “Use Option as Meta Key” enabled. However, you’re not done. You still won’t be able to bind

Basic Launch Commands

vim -x text.txt
# start vim in encrypted mode
vim -d file1.txt file2.txt
# start vim in diff mode
vim -e text.txt
# start vim in ex mode
vim -v text.txt
# start vim in vi mode

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 mode is confusingly also referred to as command-line mode since it can be invoked directly from the command line ex file.txt or vim -E file.txt

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
  1. $ specifies the last line
(Select all lines from 10 and below)
:10,$
  1. % specifies all lines (equivalent to 1,$)
(Select all lines)
:%
  1. . specifies the current line
(Select all lines before the current line)
:1,.
  1. + specifies the next line(s)
(Select the next 10 lines, including the current line)
:.,.+10
  1. - specifies the previous line(s)
(Select the previous 10 lines, including the current line)
:.-10,.
  1. /regex specifies the next line containing the RegEx regex
(Select the first line containing `example` after the cursor current position
:/example
  1. ?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.

Namespace Type Prefix Scope
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
function-argument a: Function argument (only inside a function)
vim-variable v: Global, predefined by Vim

Examples

An example of setting variables using the let keyword

```vim
" Create a script variable called dotfiles pointing to the config directory
" this variable will not exist outside of the script it was declared in
let s:dotfiles = fnamemodify(stdpath('config'), ':h')

" Create a global variable which can be referenced later on if this file has been sourced
let g:my_variable = [1, 2, 3]
echo type(g:my_variable)
" => 3

" (More info on the type() function) (:h type)

"   type  | value | function({expr})
" ----------------------------------
" Number:     0     type(v:t_number)
" String:     1     type(v:t_string)
" Funcref:    2     type(v:t_func)
" List:       3     type(v:t_list)
" Dictionary: 4     type(v:t_dict)
" Float:      5     type(v:t_float)
" Boolean:    6     type(v:true) [or] type(v:false)
" Null:       7     type(v:null)
```

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

Note: Bash is not one of the supported languages of Markdown. Therefore, you have to map any bash code-blocks to be rendered as sh code-blocks with the syntax bash=sh

Update: If you have the latest version of vim, this is no longer necessary, the default mappings include ['c++=cpp', 'viml=vim', 'bash=sh']

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 :arrow_right: D :arrow_right: 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 Extended regular expressions, the ones that are used in egrep

Metacharacters

Edit File Remotely

Since vim runs inside a terminal, you can use vim to edit a file remotely on another computer if it has your SSH key.

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

Save & Quit

In ex mode:

In Normal mode:

Warning: Even if you haven’t made any changes, :wq will update the file’s last modified date to the current time. To avoid this, use :x

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

:pwd

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

ca w up

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

Good News: Although vim tells you that custom commands must start with an upper case letter, using cnorea allows you to bypass this rule entirely. Customize away!

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.

Tip:: You can press K in normal mode to open a help page on whatever word the cursor is currently on.

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.

Warning: This doesn’t always hold true. For instance, <C-w><C-c> won’t close the active window, but <C-w>c will. The reason is that <C-c> is the undo command, so vim decided not to rebind it.

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

|:—:|:—:|:—:| |⌃ 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]|

{: notice–info} Tip: Use :tabe file.txt to open file.txt in a new tab.

Registers

Read-Only Registers

  • ": contains the most recently executed command

  • "% contains the name of the current file

  • ". contains the most recently inserted text

Special Registers

  • "/ the most recently searched for pattern

  • # the name of the alternate file

  • "_ the black-hole register, useful for scripting when you don’t want to modify the contents of current registers

  • "+ is the computer’s clipboard. If you want to copy or paste a range of code, you can use this register to do so.

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

  • <C-r> followed by the name of a register inserts the contents of that register into the command line

  • <C-r><C-w> will insert the word currently under the cursor

  • <C-r><C-a> will insert the WORD currently under the cursor

  • <C-r><C-l> will insert the line currently under the cursor

  • <C-r><C-p> will insert the file under the cursor

  • @a will execute the contents of register @a as a series of normal mode commands

  • Setting the contents of the search register:

    let @/ = '<pattern>'
    
  • You can repeat the last : command in normal mode by typing @:

  • You can repeat the last register referenced via normal mode’s @ by typing @@

Copying to Clipboard

  1. Normal Mode

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

  • Copying the contents of the active buffer to the clipboard

    gg"+yG
    
  1. Command-line Mode

Use the :y[ank] comamnd

  • Copying the contents of the active buffer to the clipboard

    :%y+
    

Writing to registers

The @/ register stores the last search pattern

  • Modifying the most recently searched item

    let @/ = "\<word\>"
    
  • Copy each match to /pattern/ as a line in register @a

    :global /pattern/ normal "AY
    
  • Paste the previous pattern searched for in a command

    " Paste the pattern stored in the "/ register
    %s_<C-r>/_
    
  • Open the help page for the contents of register "

    " Actually input a <C-r> here
    :help <C-r>"
    

vimdiff

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

  • Launching vim in diff mode

    vim -d old.txt new.txt
    

Filepath Shortcuts

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

  • %:. the filepath relative to the current directory vim.md

  • %:~ the filepath relative to the home directory ~/notes/_pages/vim.md

  • %:p the absolute filepath /Users/atraver/notes/_pages/vim.md

  • %:r the filename root, without the extension vim

  • %:e the filename extension, without the root md

expand() Selectors

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

" :h :<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:

  • %p:h the :h will return everything left of the right-most /, in this case being /Users/austin/notes/_pages

  • %p:t does the exact same thing, but will return everything right of the right-most /, in this case being vim.md

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.

  • iw specifies the inner word, which is the word but not the surrounding whitespace.

  • iW specifies the same thing, but includes non-word characters, selecting everything up to the surrounding whitespace.

  • aw specifies a word and will include the surrounding whitespace.

  • aW specifies a word, including non-word characters up to the whitespace, and including the whitespace

  • is specifies the inner sentence and will match everything in the sentence, up to but not including the surrounding whitespace.

  • as specifies the inner sentence and will match everything in the sentence, including the surrounding whitespace.

  • c The change command can be chained with i/a to specify boundary, and w/s/p to specify scope of word, sentence, or paragraph accordingly.

  • ( Go to the previous sentence.

  • ) Go to the next sentence.

  • { Go to the previous paragraph.

  • } Go to the next paragraph.

Here are some additional examples:

  • ci": Change the text inside the first double-quoted phrase in the line.

  • ci': Change the text inside the first single-quoted phrase in the line.

  • ct:: Change the text from the cursor right up to the next : to the right.i

  • %: Not really a motion command, but it will go to the matching (, {, [``), }, or ] character.

  • [{: Go to the previous unmatched { character.

  • [(: Go to the previous unmatched ( character.

  • ]}: Go to the next unmatched } character.

  • ]): Go to the next unmatched ) character.

  • *: Go to next match of the current word.

  • #: Go to previous match of the current word.

  • /pattern: Go to the beginning of the match to pattern.

  • /pattern/e: Go to the end of the next match to pattern.

  • ?pattern?e: Go to the end of the next match to pattern.

  • "*diw will delete the inner word, and copy it to the clipboard. "* being where the clipboard is stored.

  • di[ will delete everything inside the brackets. This can also be di] and to my knowledge they are not different.

  • da[ will delete everything inside the brackets including the brackets.

  • ci} will delete everything inside of the curly braces and enter insert mode.

  • ca} will delete everything inside of the curly braces including the braces and enter insert mode.

  • dit will delete everything inside a tag block (e.g. <div> test </div>)

  • dat will delete a tag block (e.g. <div> test </div>)

  • d/pattern will delete everything from the cursor forward to the next match.

  • d?pattern will delete everything from the cursor back to the last match.

  • dgn will delete the next match search pattern match

  • cgn will change the next search pattern match

  • gnD will delete the entire line containing the next match to the current pattern.

  • ndw will delete the entire word corresponding to the next instance matching the pattern.

  • d* will delete everything between the current word and the next match of the current word in the file.

  • d# will delete everything between the current word and the previous match of the current word in the file.

  • d$ will delete everything to the end of the line.

  • dg$ will delete everything to the end of the visual line, (if there is soft wrapping, it will not continue to delete the content of the line below).

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

  • yst." will surround the selection from the cursor to the next . with double-quotes.

  • ysiw) will surround the (word) in parentheses like so.

  • ysiw( will surround the word in parentheses, but also add whitespace padding between the ( word ) as so.

  • ysiw<div> will surround the

    word
    like so.

  • ds" will remove the inner-most double quotes selection.

  • cs"' will change the inner-most double quotes to single quotes.

Searching

  • Add :set hlsearch to your ~/.vimrc to highlight text matching the current search pattern.

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

  • ggn: Go to the first match
  • GN: Go to the last match
  • n: Go to the next match
  • N: Go to the previous match

Marking

Key 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
d`a delete from current cursor position to position of mark a
c’a change text from current line to line of mark a
y`a yank text to unnamed buffer from cursor to position 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

  • gg"*yG will yank the entire file to the system clipboard.

Special Insert Mode

  • Insert a 1-byte character a literally

    <C-v>a
    a
    
  • Insert a 1-byte character a by its hexadecimal value

    <C-v>x61
    " a
    
  • Insert a 2-byte UTF-8 character by its character code

    <C-v>u7231
    " 爱
    
  • Insert a 4-byte UTF-8 character 😂 by its character code

    <C-v>U0001f602
    " 😂
    

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.

Getting Started

  • vi .: open up the file explorer upon launching, starting in the present working directory.

  • :Tex: open up the file explorer in a new tab.

  • :Lex: open up the file explorer on the left-side

  • :Rex: return to an existing file explore window

Moving Files

  • mf: Mark file
  • mF: Unmark a file
  • mp: Print marked files
  • mt: Mark target destination
  • mm: Move all marked files into the marked target destination
  • mc: Copy all marked files into the marked target destination

Creation/Deletion

  • %: Create file
  • d: Create directory
  • D: Delete file
  • R: Rename file
  • X: Execute current file
  • x: Run current file using specified program

String Manipulation

  • Performing brace expansion

    echo split(expand("hunt{er,ed,ing}"), '\n')
    " => ['hunter', 'hunted', 'hunting']
    
  • Performing filename expansion

    echo expand("~/Documents/file.txt")
    " => '/Users/austin/Documents/file.txt'
    
  • Performing environment variable expansion

    echo expand("$HOME/Desktop/picture.jpg")
    
    let g:other_file = expand("%:p:h") . "/other.txt"
    " Modifiers:
    " %         Relative path to the current file
    " :p		Expands to the absolute path
    " :h		Expands to the head (the parent directory of the file)
    " :t		Expands to the tail (the file, without the preceding directories)
    " :r		Expands to the root of the filename (the filename, without the '.ext'
    " :e		Expands to the just `.ext` of the filename extension only
    
  • Querying the directories of the XDG Base Directory Specification

    echo stdpath("config")
    " => '/Users/austin/.config/nvim'
    
    echo stdpath("data")
    " => '/Users/austin/.local/share/nvim
    
    echo stdpath("cache")
    " => '/Users/austin/.cache/nvim
    
  • Adding the subdirectories /vim and /vim/after to the config variable &runtimepath

let &runtimepath .= ','.join(split(expand($XDG_CONFIG_HOME ."/vim{,/after}"),'\n'), ',')
  • Adding the parent directory of the subdirectory found using stdpath
" (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
" :h 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

" :h command-nargs
" :h q-args
" Create a command (with tab completion) for opening wiki posts
command -nargs=1 -complete=file_in_path Jot call Jotf(<q-args>)
  • The <q-args> parameter will tell Vim that you’d like to pass in the argument as a string. If you’d like Vim to think you’ve passed in a variable declared in the environment, use <args> instead.

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

  • <C-g>: Go to next match
  • <C-t>: Go to previous match

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

  • :help reference_toc

  • :help /[: Help on a character when used for search patterns

  • :help -r: Help on a character passed as a command line flag

  • :help c_<CR>: Help on the return key when pressed during command mode

  • :help :echo: Help on the echo command

  • :help 'option': Help on a particular option

  • Creating help files: add-local-help and write-local-help and help-writing

Useful Command Flags when Opening Vim

  • Reference: :help starting.txt

  • Open each file in its own tab

:help -p

vim -p ./*.md


* Open each file in the same window, split horizontally
# :help -o
vim -o ./*.md
</code></pre><ul>
<li>
<p>Open each file in the same window, split vertically</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh"><span class="c1"># :help -O</span>
vim -O ./*.md
</code></pre></div></li>
<li>
<p>Open each file in its own tab</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh"><span class="c1"># :help -p</span>
vim -p ./*.md
</code></pre></div></li>
<li>
<p>Open a file with the cursor starting on line 13</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh"><span class="c1"># :help -+</span>
vim <span class="s1">&#39;+13&#39;</span> file.txt
</code></pre></div></li>
<li>
<p>Open a file with the cursor starting on the first match to <code>pattern</code></p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">vim <span class="s1">&#39;+/pattern&#39;</span> file.txt
</code></pre></div></li>
<li>
<p>Open a file and immediately execute a command</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh"></code></pre></div></li>
</ul>
<h1 id="using-">Using <code>+</code></h1>
<p>vim &lsquo;+echo &ldquo;hello&rdquo;&rsquo; file.txt</p>
<h1 id="using--c">Using <code>-c</code></h1>
<p>vim -c &lsquo;echo &ldquo;hello&rdquo;&rsquo; file.txt</p>
<pre><code>
* Open a file, and save the commands typed

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

```sh
# -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
</code></pre><ul>
<li>Open a file, and execute the commands as input to normal mode of the file <code>inputs.vim</code></li>
</ul>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">vim -s <span class="s1">&#39;inputs.vim&#39;</span>
</code></pre></div><h2 id="useful-help-pages">Useful Help Pages</h2>
<ul>
<li><code>:help list-functions</code></li>
<li><code>:help key-notation</code></li>
</ul>
<h2 id="navigating-compressed-files">Navigating Compressed Files</h2>
<ul>
<li>
<p>You can use vim to edit compressed files (e.g. <code>.gz</code>, <code>.tar</code>, and <code>.zip</code>)</p>
</li>
<li>
<p>Reference <code>:help pi_gzip.txt</code></p>
</li>
<li>
<p>Reference <code>:help pi_tar.txt</code></p>
</li>
<li>
<p>Reference <code>:help pi_zip.txt</code></p>
</li>
</ul>
<h2 id="jump-motions">Jump Motions</h2>
<p>Useful to check out <code>:help jump-motions</code></p>
<ul>
<li><code>ge</code>: Move back to the end of the previous word</li>
<li><code>gE</code>: Move back to the end of the previous WORD</li>
<li><code>)</code>: Move to the next sentence.</li>
<li><code>'.'</code>: Move to where the last change was made</li>
<li><code>&lt;C-o&gt;</code>: Go to previous jump</li>
<li><code>&lt;C-i&gt;</code>: Go to next jump</li>
<li><code>g;</code>: Go to where the previous change was made</li>
<li><code>g,</code>: Go to where the next change was made</li>
<li><code>]m</code>: Go to next function/method</li>
<li><code>[m</code>: Go to previous function/method</li>
<li><code>H</code>: Go to the top of the window</li>
<li><code>M</code>: Go to the middle of the window</li>
</ul>
<h2 id="quickly-open-help">Quickly Open Help</h2>
<ul>
<li>In normal mode, you can view a help page for the word under the cursor by pressing <code>K</code></li>
</ul>
<h2 id="setting-keybindings">Setting Keybindings</h2>
<ul>
<li>
<p>Setting a keybinding to execute something in command mode</p>
<div class="highlight"><pre class="chroma"><code class="language-vim" data-lang="vim"><span class="c">&#34; Only set the mapping for this &lt;buffer&gt;</span><span class="err">
</span><span class="err"></span><span class="nx">nnoremap</span> <span class="p">&lt;</span><span class="nx">buffer</span><span class="p">&gt;</span> <span class="nx">GG</span> <span class="p">&lt;</span><span class="nx">CMD</span><span class="p">&gt;</span><span class="nx">echo</span> <span class="s1">&#39;woah&#39;</span><span class="p">&lt;</span><span class="nx">CR</span><span class="p">&gt;</span><span class="err">
</span></code></pre></div></li>
</ul>
<h2 id="completion">Completion</h2>
<ul>
<li>
<p><code>:h ins-complete-menu</code></p>
</li>
<li>
<p>Set the maximum height of the completion menu to 10 rows</p>
<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh"><span class="nb">set</span> pumheight <span class="m">10</span>
</code></pre></div></li>
</ul>
<h2 id="substitution">Substitution</h2>
<h3 id="substitute"><code>:s[ubstitute]</code></h3>
<p>The <code>:s[ubstitute]</code> command is incredibly useful, some examples included below:</p>
<ul>
<li>
<p>Substitute matches to pattern with <code>replacement</code></p>
<div class="highlight"><pre class="chroma"><code class="language-vim" data-lang="vim"><span class="c">&#34; One match, the current line</span><span class="err">
</span><span class="err"></span><span class="nx">substitute</span> <span class="sr">/pattern/</span><span class="nx">replacement</span><span class="err">
</span><span class="err"></span><span class="c">
</span><span class="c">&#34; All matches, the current line</span><span class="err">
</span><span class="err"></span><span class="nx">substitute</span> <span class="sr">/pattern/</span><span class="nx">replacement</span>/<span class="nx">g</span><span class="err">
</span><span class="err"></span><span class="c">
</span><span class="c">&#34; All matches, every line</span><span class="err">
</span><span class="err"></span>% <span class="nx">substitute</span> <span class="sr">/pattern/</span><span class="nx">replacement</span>/<span class="nx">g</span><span class="err">
</span><span class="err"></span><span class="c">
</span><span class="c">&#34; One match, current line, case insensitive</span><span class="err">
</span><span class="err"></span><span class="nx">substitute</span> <span class="sr">/\cpattern/</span><span class="nx">replacement</span>/<span class="nx">g</span><span class="err">
</span><span class="err"></span><span class="c">
</span><span class="c">&#34; One match, current line, case sensitive</span><span class="err">
</span><span class="err"></span><span class="nx">substitute</span> <span class="sr">/\Cpattern/</span><span class="nx">replacement</span>/<span class="nx">g</span><span class="err">
</span></code></pre></div></li>
</ul>
<h3 id="substitute-1"><code>substitute()</code></h3>
<p>The <code>substitute(expression, pattern, replacement, flags)</code> function is also very useful, some examples below:</p>
<ul>
<li>
<p>Substitute first match of <code>&lt;expr&gt;</code> with <code>&lt;replacement&gt;</code></p>
<div class="highlight"><pre class="chroma"><code class="language-vim" data-lang="vim"><span class="k">let</span> <span class="nx">sentence</span> <span class="p">=</span> <span class="s1">&#39;the quick brown fox jumped over the lazy dog&#39;</span><span class="err">
</span><span class="err"></span><span class="nx">echo</span> <span class="nx">substitute</span><span class="p">(</span><span class="nx">sentence</span><span class="p">,</span> <span class="s1">&#39;\&lt;the\&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="err">
</span></code></pre></div><div class="highlight"><pre class="chroma"><code class="language-txt" data-lang="txt">a quick brown fox jumped over the lazy dog
</code></pre></div></li>
<li>
<p>Substitute every match of <code>&lt;expr&gt;</code> with <code>&lt;replacement&gt;</code></p>
<div class="highlight"><pre class="chroma"><code class="language-vim" data-lang="vim"><span class="k">let</span> <span class="nx">sentence</span> <span class="p">=</span> <span class="s1">&#39;the quick brown fox jumped over the lazy dog&#39;</span><span class="err">
</span><span class="err"></span><span class="nx">echo</span> <span class="nx">substitute</span><span class="p">(</span><span class="nx">sentence</span><span class="p">,</span> <span class="s1">&#39;\&lt;the\&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;g&#39;</span><span class="p">)</span><span class="err">
</span></code></pre></div><div class="highlight"><pre class="chroma"><code class="language-txt" data-lang="txt">a quick brown fox jumped over a lazy dog
</code></pre></div></li>
</ul>
<h3 id="replacement-expessions-">Replacement Expessions <code>\=</code></h3>
<ul>
<li>
<p><code>:h sub-replace-expression</code></p>
</li>
<li>
<p>Substitute all matches with the result of <code>&lt;expression&gt;</code></p>
<div class="highlight"><pre class="chroma"><code class="language-vim" data-lang="vim"><span class="c">&#34; In this case, &lt;expression&gt; is expand(&#34;~&#34;)</span><span class="err">
</span><span class="err"></span>% <span class="nx">substitute</span> <span class="sr">/pattern/</span>\<span class="p">=</span><span class="s1">&#39;Directory &#39;</span> . <span class="nx">expand</span><span class="p">(</span><span class="s2">&#34;~&#34;</span><span class="p">)</span>/<span class="nx">g</span><span class="err">
</span></code></pre></div></li>
</ul>
<h3 id="abandon-git-commit">Abandon Git Commit</h3>
<p>If you want to prevent Git from committing after editing the commit message, do:</p>
<pre><code>```vim
:cq[uit]

This will make Vi quit with an error code, preventing the commit operation from proceeding

Clearing Current File

  • Edit a new, unnamed buffer

    ene[w]
    
    
    

Setting the File Name

  • Change the file name of the current buffer to file.txt

    f[ile] file.txt
    
    
    
  • Remove the name of the current buffer

    0f[ile]
    
    
    

View Wordcount

  • View the amount of words written in the current file

    g <C-g>