Vim

Command line, ubiquitous text editor

If you have terminal access, you generally are going to have vim. That means learning it as a powerful command line text editing, searching and manipulation tool is always going to be useful.

There are different versions, ranging from vi through to modern vim.

Vim can be extended with various plugins though it is suggested you learn the basics before looking to extend it. Plugins are not likely to be available on a server so it is important you know how to get the most out of the core functionality.

Learning

There are a few ways to learn vim.

Vimtutor

Simply open a terminal and type vimtutor and it will open vim with a text file loaded. You should read through this text file and work through the steps.

This will give you a basic introduction to vim

Modes

There are two main modes in Vim:

See:

(Normal|Command) Mode

This is the mode you start with when you open Vim. You can move around and can issue commands

Insert Mode

In this mode, you are actually editing text, you have a few ways of entering insert mode:

  • [i] will enter insert mode at the current cursor position
  • [o] will create a new line under the cursor position and enter insert on that new line
  • [c] + [e] will delete the word under the cursor and put you into insert mode

To exit insert mode, simply hit [escape]

(Command-line|Cmdline|Last Line) Mode:source ~/.vimrc

In this mode you enter commands in the last line of vim. You enter this from normal mode by typing :

This is how you quit vim, amongst other things

Configuration

Vim is very configurable. Some basic configuration is likely to be the same for all of us. Other items are going to be more personal preference.

On the Fly Configuration

You can adjust configuration on the fly by typing : set followed by some configuration options

Persistent Configuration

To make persistent configuration changes, you should edit your .vimrc file.

As standard, the .vimrc file live in your home directory, eg cd ~i

Global Persistent Configuration

To have one set of vim configuration that you share between users (eg root, you), then you can create a file called /etc/vimrc

If this file already exists, then you probably want to back it up first: sudo bash -c "mv /etc/vimrc /etc/vimrc.bak"

This should be automatically brought in however you can also source this global configuration into each user .vimrc file using source

Some Suggested Configuration

Here are some basic .vimrc configuration options that you are probably going to want to implement:

Tabs to 4 Spaces

Indents to 4 spaces, entered by pressing the tab key

1
set tabstop=8 softtabstop=0 expandtab shiftwidth=4 smarttab

Suggested Full Basic Configuration

As far as I'm concerned each of these are require to make vim more useful, you may disagree

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
" Use Vim settings, rather then Vi settings (much better!).
" This must be first, because it changes other options as a side effect.
set nocompatible

" ================ General Config ====================

set number                      "Line numbers are good
set backspace=indent,eol,start  "Allow backspace in insert mode
set history=1000                "Store lots of :cmdline history
set showcmd                     "Show incomplete cmds down the bottom
set showmode                    "Show current mode down the bottom
set gcr=a:blinkon0              "Disable cursor blink
set visualbell                  "No sounds
set autoread                    "Reload files changed outside vim when you run an external command
set ruler                       "Show the cursor position at all time
set cursorline                  "Adds a line under the cursor
set ignorecase                  "Set ignorecase on.
set showmatch                   "showmatch: Show the matching bracket for the last ')'?
set ve=all                      "allow the cursor to go beyond the end of the line
set hidden                      "open a new buffer without saving the current one
" case insensitive tab completion, if enabled
if exists("&wildignorecase")
    set wildignorecase
endif

"turn on syntax highlighting
syntax on
sytax sync fromstart

sytax sync fromstart
" ================ Turn Off Swap Files ==============
" Only do this if you also use the Persistent Undo Below

set noswapfile
set nobackup
set nowb

" ================ Persistent Undo ==================
" Keep undo history across sessions, by storing in file.
" Only works all the time.

silent !mkdir ~/.vim/backups > /dev/null 2>&1
set undodir=~/.vim/backups
set undofile

" ================ Indentation ======================

set autoindent
set smartindent
set smarttab
set shiftwidth=4
set softtabstop=4
set tabstop=4
set expandtab

filetype plugin on
filetype indent on

" Display tabs and trailing spaces visually
set list listchars=tab:\ \ ,trail:ยท

" ================ Folds ============================

set foldmethod=manual   "Only fold when told to - see here http://vim.wikia.com/wiki/Folding

" ================ Completion =======================

set wildmode=list:longest
set wildmenu                "enable ctrl-n and ctrl-p to scroll thru matches
set wildignore=*.o,*.obj,*~ "stuff to ignore when tab completing
set wildignore+=*vim/backups*
set wildignore+=*sass-cache*
set wildignore+=*DS_Store*
set wildignore+=vendor/rails/**
set wildignore+=vendor/cache/**
set wildignore+=*.gem
set wildignore+=log/**
set wildignore+=tmp/**
set wildignore+=*.png,*.jpg,*.gif

" ================ Scrolling ========================

set scrolloff=8         "Start scrolling when we're 8 lines away from margins
set sidescrolloff=15
set sidescroll=1

" This will open the current file in PHPStorm when you press <Ctrl>F
" You will need this plugin installed https://plugins.jetbrains.com/plugin/6027-remote-call
nmap <silent> <C-F> :!curl localhost:8091?message=%:p<CR><CR>

"Use <Ctrl> J,K,L,H to move around split windows
nnoremap <C-J> <C-W>J<CR>
nnoremap <C-K> <C-W>K<CR>
nnoremap <C-L> <C-W>L<CR>
nnoremap <C-H> <C-W>H<CR>

" type cd in normal mode to switch the pwd to that of the file
nmap <silent> cd :cd %:h<CR>

" For some reason vim doesn't recognise md files as markdown. Lets correct that
au BufNewFile,BufRead *.md set filetype=markdown
" And add syntax highlighting for code blocks
let g:markdown_fenced_languages = ['bash=sh', 'css', 'django', 'javascript', 'js=javascript', 'json=javascript', 'perl', 'php', 'python', 'ruby', 'sass', 'xml', 'html']

" =============== Spelling ==========================

set spelllang=en_gb

" Create and use spelling directory
silent !mkdir -p ~/.vim/spell > /dev/null 2>&1
set spellfile=~/.vim/spell/en.utf-8.add

" Enable spelling automatically for markddown and git commits
autocmd BufRead,BufNewFile *.md setlocal spell
autocmd FileType gitcommit setlocal spell

" Allow speling based completion
set complete+=kspell

" Ignore CamelCase words when spell checking
fun! IgnoreCamelCaseSpell()
  syn match CamelCase /\<[A-Z][a-z]\+[A-Z].\{-}\>/ contains=@NoSpell transparent
  syn cluster Spell add=CamelCase
endfun
autocmd BufRead,BufNewFile * :call IgnoreCamelCaseSpell()

These are more optional, and may not be needed

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
" If we want to use encryption, lets use the latest version
" see here for details http://vim.wikia.com/wiki/Encryption
set cm=blowfish2

" Change leader to a comma because the backslash is too far away
" That means all \x commands turn into ,x
" The mapleader has to be set before vundle starts loading all
" the plugins.
let mapleader=","

set nowrap       "Don't wrap lines
set linebreak    "Wrap lines at convenient points if manually told to

" ====== Use Alt-arrow to move around windows ======
nmap <silent> <A-Up> :wincmd k<CR>
nmap <silent> <A-Down> :wincmd j<CR>
nmap <silent> <A-Left> :wincmd h<CR>
nmap <silent> <A-Right> :wincmd l<CR>

" The keys `jj` don't really appear in english, so use this as a quick way to
" simulate esc
imap jj <esc>
vmap jj <esc>

" Press `sf` to format SQL need this installed first
" https://github.com/vim-scripts/SQLUtilities
vmap <silent>sf        <Plug>SQLUFormatter<CR>
nmap <silent>sf        <Plug>SQLUFormatter<CR>

Vim with Mouse

To use your mouse more fluently with vim, add the following to your ~/.vimrc file

1
2
3
" ====== Enable Mouse ===

se mouse+=a

Once this is enabled, you can do things like:

  • use your mouse to select words, lines and blocks of text
  • place the cursor at a specific point

However it does cause some issues which you need to work around.

Copying/Pasting Outside Vim

If you want to select some text in order to copy/paste it somewhere outside of vim (i.e. not yanking in vim but using standard Linux clipboard), then simply:

  • hold down the [shift] key
  • highlight desired text to copy
  • use middle mouse button to paste text elsewhere

Alternatively, you can get vim to use the X clipboard. This requires that vim has been compiled with clipboard. You can check if this is the case be running the following

1
vim --version | grep clipboard

If this is empty then you need to download a version of vim that has it. The easiest way of doing this is install gvim which will install a CLI version that supports this

You then have access to the + (the XA_SECONDARY clipboard) and * (the XA_PRIMARY clipboard) registers, see here for more details

If you want you can even add the following to your ~/.vimrc file, or set it manually, and get vim to use the same clip board as CTRL+V

1
set clipboard=unnamedplus

Warning

This uses the X clipboard, and has not been tested when using Wayland

Tip

If you are using Wayland, don't

Changing Colour Schemes

Vim comes with a selection of colour schemes built in as standard.

Selecting a built in colour scheme

To see all available, use:

1
:colo [TAB]

To select and use one, use:

1
:colo torte

To permanently use one, just put the above command in your ~/.vimrc file

Helpful config that doesn't live in your vimrc

Spell

When working on a file, you may want to make sure it is spelt correctly, i.e. when working on handbook entries

To do this, enter the following in normal mode :set spell

This will highlight works that are spelt incorrectly, as well as some grammatical mistakes.

To jump to the next mistake press ]s, to jump to the previous one press [s

When hovering over a misspelt word press z= to bring up a list of suggestions. Simply press the number to to the correct word and it will be updated

See :help spell for more

Clear search highlights

Vim should have been configured to highlight what you have searched for. Sometimes you may want to get rid of this, but still keep the search term in the register.

To do this simply run :set nohighlight, or :set noh for short, and the highlights will be cleared until you run another search.

Diffing files

Sometimes you may want to visually diff two files. To do this quickly do the following

  • Open the first file
  • Open the second file in a vertical split :v /path/to/file
  • Tell vim to diff the two open buffers :windo diffthis
  • Jump around the diffs using [c and ]c
  • Copy changes between the files using do (diff obtain) and dp (diff put)
  • Leave diff mode by running :windo diffoff

See :help diff for more

Changing the current working directory

Vim will set the working directory to the one that you ran it from. If you want to use the gf command to jump to relative files this may not always be the right one

To change this, type the following cd /path/to/dir

I often use this when working with nginx files. The files that I'm editing are in the conf.d/ directory, but the path to the includes is /etc/nginx

Switching to the directory allows you to move the cursor over any include file and press gf to jump to it

Helpful commands

Insert File Paths

In insert mode, if you want to complete a path you can hit [ctrl]+[x] [ctrl]+[f] to get a neat little drop down that lets you pick the file.

Reload the file

If you know that the currently open buffer has been changed on disk, you may want to reload it to see what has changed.

This can be done by running :e, or :e! if there are changes that you want to discard

Jumping between buffers

Vim is able to open multiple files at once, these open files are called buffers. This can happen if you run vim file1 file2 ... fileN, if you open files after starting vim :e file, :vs file, or create new files :enew, :vnew. You can use the following commands to move between these open files

  • :bn This will move you to the next buffer
  • :bp This will move you to the previous buffer
  • :ls This will give you a numbered list of all open buffers along with some information about their state
  • :b This will open a buffer by number or name. You can type a couple of letters and press tab to get the name

Text Manipulation

The following commands are used for basic text manipulation

Yank

The y key is used to yank text into the register. This leaves the text in the document, and allows you to paste is later on

Delete

The d key is used to delete the text from the document and place it into the register

Paste

The p key is used to paste the register into the document. By default this will paste the 0 register onto the page, but it is possible to paste others by pressing " + <reg> + p

Here are some useful registers that you may want to use

  • / The last search term
  • : The last command
  • * and + The xclipboard - will explain this further down
  • % The current filename
  • # The last opened buffer filename
  • 0 The last yanked / deleted text - this is useful if you are using the register in the search / command line.

Tip

To use the registers in the search / command line press <Ctrl> + r + <reg>

To see all of you registers type :reg

Movement

Blocks

You can use the { to jump up a block, and the } to jump down a block.

A block is considered to be any block of text that doesn't start with a blank line, i.e.

1
2
3
4
5
6
test test test test test test test test test test
test test test test test test test test test test
All of this is one block
test test test test test

This is a new block

Start of Line

You can use ^ to jump to the start of a line, or <Shift> + i to start editing at the start of it, both of these will take you to the first non space character of the line. If you need to jump to the very first character of the line, then you can press 0

End of Line

Press $ to jump to the end of the line, or <Shift> + a to start editing.

Jump to last edit

If you are in the middle of editing something, and then move to a different location and edit there, you can jump back the first place by pressing `` (two backticks)

Making a mark

The last edit is a special type of mark that vim uses. You can set your own marks by pressing m and then a single character, either upper or lower case, for example z

Once this is done you can then return to either the start of that line by pressing 'z or the exact place by pressing `z, (backtick + z)

Start of a file

Press gg to jump to the very start of a file

End of a file

Press G to jump to the last line of a file

Forward a word

Press w to jump forward to the next bit of a word, i.e. a / or W to jump to the next space

Backwards a word

Press b to jump to the previous bit of a word, or B to jump to the previous space

Searching

Press f + <character> to search for the next instance of the character. After that press ; to jump to the next one and , to jump to the previous one

Use F to search in reverse, i.e. backwards

Combining Movement and Commands

One of the most useful things that vim offers is the ability to combine commands. To explore this we will look at different ways to delete a block of text.

Let's consider the following block of text and the different ways that we could delete it

1
2
3
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text __your cursor is  here __text text text text text text text text text text
text text text text text text text text text

Hold down delete and then backspace

This will work, but you should feel bad about yourself if you use it

Special delete command

Typing dd will delete the entire line. You could type this several times, to remove the lines one by one.

Delete lots of words

You are able to add the number of times that you want an action to be carried out. This means that you could type 25dW and we would delete 25 words from the cursor. This is useful if you know the exact number of times you want to carry out the action, but in this case we would be guessing.

Alternatively, you could type the following k3dd, which would move you up one line, and then delete the next three lines

Jump to the start of the block and delete a block

You could run, {d} which will go to the start of the block and delete one entire block.

Delete inside or around the paragraph

Running dip will delete inside the paragraph, whilst dap will delete around the paragraph. The inside / around movements can be combined with lots of helpful modifiers, these are some of the ones I use the most

  • { or } curly braces
  • [ or ] square braces
  • ( or ) brackets
  • ' single quotes
  • " double quotes
  • < or > angle brackets
  • t and XML tag
  • w and W words

Using Visual Mode

Pressing <Ctrl> + v will put you into visual mode. This will allow you to move around and select exactly what you want. You can then press d, or x to delete the selected text

Using Visual Block Mode

You could also press <Ctrl> + <Shift> + v to enter visual block mode. This lets you draw rectangles to select rather than following the sentence structure. This is very useful when you want to remove columns of data

Shell Commands

Vim allows you to run shell commands over blocks of text. This can be entered into a range on the command line, or you can combine the ! key with a movement, which is what I use.

In addition to the inside / around commands, and the up and down blocks, you can also press ! + left / right arrow to select the current line.

This will change the command line to the following, :.!. You can then type in a bash command and it will be run on the line.

For example consider the following log entry

1
[2017-10-16 14:27:32] INFO: With this body {"products":[{"qty":1,"id":"6","configurable_options":[{"code":"colour","value":"9"},{"code":"size","value":"8"}],"custom_options":[]}],"customer_details":{"email_address":"test_order@example.com","customer_identifier":"any_unique_random_string","first_name":"John","last_name":"Smith","has_loyalty_card":1,"loyalty_card_number":"123456789"},"address_details":{"street_1":"123 Main Street","street_2":"","city":"Leeds","region":"West Yorkshire","country":"United Kingdom","post_code":"LS1 2AB"},"appId":"test,"merchantId":"4"} []

We want to be able to read the JSON that has been sent through, but it has been minified onto one line.

Combining what we have learn above, we can run the following commands - assuming that we are on the first character of the line

  • f{ - this will move the character to the opening curly brace
  • ya{ - this will yank everything inside the curly braces into the register
  • enew - this will open a new buffer
  • p - paste the register into the new file
  • ! + left arrow - tells vim we want to run a command on the current line
  • json_reformat - a bash command that will prettify JSON
  • set filetype=json - tells vim that the file contains JSON and syntax highlights it.

In additon to the json_reformat toll, I find the following commands helpful

xmllint

Like json_reformat this is used to format XML. The following is the standard command that I use

1
xmllint --format -

Which will validate and format any XML that is passed to it.

fmt

Useful to ensure that the width of a document doesn't exceed a set amount. Splits intelligently on word breaks, and can either reflow an entire document, or keep the existing line breaks

1
fmt -w 140 -s

column

Used to create text tables from deliminated data. The deliminater can be set, which makes it easier to read and edit CSV files. Use this in combination with visual block mode to easily add, move, or remove columns

1
column -s ',' -t

sort

There are other options available, but this is still the one that I turn to. Quickly sort a set of data, I use this a lot in combination with the inside braces / tags to keep definitions in alphabetically order

1
sort

uniq

Only output the unique values in a sorted list, can be used to count them as well

1
uniq (-c)

Still to do

  • Other useful bash commands
  • Folding
  • Search / replace
  • Global command
  • Read command
  • Macros
  • Indentation
  • Helpful shortcuts
  • History commands i.e. undo / redo
  • Encryption
  • Running commands on the file
  • The clipboard and how to use it