Introduction

Vim is a modal text editor, to learn how to switch modes, start by the section Switch between navigation and editing mode. Large part of this documents have been copied from the vim help accessible through:

:help <topic>

People that I admire use vim.

Configure vim in .vimrc

See also my vimrc file stored in setup/.vimrc. Many configuration options are mentioned throughout this document.

Reload the configuration after editing it:

:so ~/.vimrc

Text colour. Add syntax highlight to your .vimrc

syntax enable

File specific .vimrc options

How to add a file extension to vim syntax highlight

au BufNewFile,BufRead *.dump set filetype=sql

I used it to display markdown files as text files:

au BufNewFile,BufRead *.md set filetype=txt

Make a key combination specific to latex files, to insert a citation key using the vimtex plugin. Note: ctrl-space appears as ctrl-@ in my terminal

au BufRead,BufNewFile *.tex inoremap <C-Space> <C-x><C-o> | inoremap <C-@> <C-x><C-o>

Prevent tab expanding to space in make files SO answer:

autocmd FileType make set noexpandtab

Keyboard AZERTY, QUERTZ

I mapped m to the end of line, maybe I should use m instead?

noremap m $

See also mapping below.

Colour themes

Be sure to set terminal colour to 256 as explained in an answer to a question on vi.stackexchange and in the vim wiki 256 colors in vim

set t_Co=256

For a while I used:

set background=dark
colorscheme jellybeans

Create your own commands

A command that reuses another command can be entered directly after the command name, separated by a space. To enter normal and insert mode command, you need to prefix it with “normal”. See :help normal for more information on executing normal mode commands typed on the command line.

Sample commands that I have in my .vimrc.

Add the current date

command! Date put =strftime('%Y-%m-%d')

Convert the current line to snake case (1) replace any non alphanumeric characters by underscores (2) convert to lower case.

command! -range=% Snake s/[^a-zA-Z0-9]\+/_/g | normal Vu

Lexplore with a 30 character size buffer only

command! Ll Lexplore | vert res 30

Display a word diff

command! Gwdiff vert term git diff --word-diff

Create a table of content command based on different tools that depend on the file type

augroup Toc
    autocmd!
    autocmd Filetype markdown command! -buffer Toc Voom
    autocmd Filetype rmd command! -buffer Toc Voom
    " rnoweb are the Rnw notebooks mixing latex and R code
    autocmd Filetype rnoweb command! -buffer Toc Voom
    autocmd Filetype tex command! -buffer Toc VimtexTocOpen
augroup END
command! TOc Toc

Title inside a script

autocmd FileType python command! Title normal A #<esc>yyppv$r#kkv$r#

Right align columns in tab separated files generated by Nvim-R. After pressing the r v comment to view a data frame.

command! Tt Tabularize /\t/r0

Key mapping and shortcuts

See

:help map

Show all mappings including commands:

:map

How to map the ALT key Explains who to see what key combination is actually seen by the console:

sed -n l

I used this mapping “ALT-;” to insert the pipe “%>%” in R documents:

" The ALT key is mapped to escape in the terminal, remap it
" https://vi.stackexchange.com/questions/2350/how-to-map-alt-key
execute "set <M-;>=\e;"
autocmd FileType r inoremap <M-;> <space>%>%<CR>
autocmd FileType rmd inoremap <M-;> <space>%>%<CR>

This didn’t work because the CTRL-; is seen as ; by the terminal:

" Try to map the CTRL+;
autocmd FileType r inoremap <C-;> <space>%>%<CR>
autocmd FileType rmd inoremap <C-;> <space>%>%<CR>

In the end I changed the mapping > to %>% as explained in NVimR issue 85:

autocmd FileType r inoremap <buffer> > <Esc>:normal! a %>%<CR>a 
autocmd FileType rmd inoremap <buffer> > <Esc>:normal! a %>%<CR>a 

different mappings for CTRL+A and CTRL+SHIFT+A It’s generally not possible.

Minimal .vimrc for bug reports

You can create a minimal .vimrc and use is by calling vim with

vim -u /tmp/.vimrc

See for example this bug report where I used this minimal vimrc file to investigate an issue with the Vimtex plugin.

set nocompatible
let &runtimepath  = '~/.vim/bundle/vimtex,' . &runtimepath
let &runtimepath .= ',~/.vim/bundle/vimtex/after'
filetype plugin indent on
syntax enable
" Use zathura as a PDF viewer
let g:vimtex_view_method = 'zathura'

Or another minimal vimrc to investigate an issue with the nvim-R plugin.

set nocompatible
let &runtimepath  = '~/.vim/bundle/Nvim-R,' . &runtimepath
filetype plugin indent on
syntax enable
let maplocalleader = ";"

" enable vim-markdown for .Rmd files too
" This might conflict with the Nvim-R plugin
augroup filetypedetect_markdown
    au!
    au BufRead,BufNewFile *.Rmd set ft=markdown
augroup END

The solution was to use 2 file types for Rmd files: set ft=rmd.markdown.

Show settings such as file type

Show existing values of settings with a question mark at the end

:set updatetime?
:set signcolumn?
:set filetype?

Convert

Pandoc

Vim uses a syntax highlight system that changes quotes and backsticks. It prevents copy pasting from vim using the tmux copy mechanism. To turn it off before a copy:

syn off

From markdown to other formats with pandoc

Convert markdown documents to other formats such as pdf with pandoc.

Convert the current document to html

:Pandoc 

Convert the current document to pdf

:Pandoc pdf

Convert the current document to word

:Pandoc docx

Other output -t options from man pandoc

• docx (Word docx) • html or html5 (HTML, i.e. HTML5/XHTML polyglot markup) • latex (LaTeX) • odt (OpenOffice text document) • pptx (PowerPoint slide show)

Add a yaml front matter to specify more parameters

---
title: "Songs of freedom"
author: "Bob Marley"
geometry: margin=0.5cm
---

bibliography

To use a bibliography with the pandoc extension insert the following in the header of the markdown file:

bibliography: /path/to/bibliography/papers.bib

Then the bibliography file should be added to the vim variable b:pandoc_biblio_bibs. You can check it was added correctly by calling:

:echo b:pandoc_biblio_bibs

Once the bibliography files is activated, autocomplete can be called by pressing CTRL-X CTRL-O (or ctrl+space in my case) after @. For more see:

:help vim-pandoc-bibliographies-module

Bibliography also works with R markdown documents, see rmarkdown documentation authoring bibliographies and citations.

Edit a text file

Edit a whole line

To edit a whole line:

dd to delete a whole line
yy to copy a whole line
p to paste the copied or deleted text after the current line or 
P to paste the copied or deleted text before the current line 

Edit multiple lines

You can edit multiple lines simultaneously by inserting text inside a multi-line selection in Vim :

Use Ctrl+V to enter visual block mode
Move down with jj to select the columns of text in the lines you want to comment.
Then hit Shift+I and type the text you want to insert.
Then press Escape, the inserted text will appear on all lines.

Similarly to enter text at the end of multiple lines (vim.wikia)

Use Ctrl+V to enter visual block mode
Move down with jj to select the columns of text in the lines you want to comment.
Then hit **$** to select all lines until the end of the line.
Then press Shift+A and type the text you want to insert.
The press Escape, the inserted text will appear at the end of all lines.

How to add text at the end of each line in Vim?

“Visual select a paragraph vip, switch to Visual block mode CTRL V, append to all lines $A a comma ,, then press Esc to confirm.”

Delete all lines that contain a pattern

Delete all lines that contain “pattern”:

:g/pattern/d

Delete all lines that do not contain a pattern:

:g!/pattern/d
:v/pattern/d

See also:

Increment numbers in a list

Use the range command as explained in the vim wiki:

:put =range(11,15)

Use the auto incrementation g CTRL-A

:help ctrl-a

    {Visual}g CTRL-A Add [count] to the number or alphabetic character in
            the highlighted text. If several lines are
                highlighted, each one will be incremented by an
            additional [count] (so effectively creating a
            [count] incrementing sequence).  {not in Vi}
            For Example, if you have this list of numbers:
                1. ~
                1. ~
                1. ~
                1. ~
            Move to the second "1." and Visually select three
            lines, pressing g CTRL-A results in:
                1. ~
                2. ~
                3. ~
                4. ~

Other example from the vim wiki:

my_array[0] = 0;

Then copy it using Y6p (copy the line and paste it six times). The result is:

my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;
my_array[0] = 0;

Then select the lines from the second line onwards and use g CTRL-A to get:

my_array[0] = 0;
my_array[1] = 0;
my_array[2] = 0;
my_array[3] = 0;
my_array[4] = 0;
my_array[5] = 0;
my_array[6] = 0;

Filter lines in a csv files

Filter a file in place (seen in a blog post called Vim Kōans)

:%!awk "/paper/{print $4}"

Sort lines alphabetically

Select a few lines in visual mode and

:sort

Help sort

With [!] the order is reversed.

    :'<,'>sort!

With [i] case is ignored.

    :'<,'>sort i

With [u] (u stands for unique) only keep the first of
a sequence of identical lines

Sort outside a pattern

When /{pattern}/ is specified and there is no [r] flag
the text matched with {pattern} is skipped, so that
you sort on what comes after the match.
Instead of the slash any non-letter can be used.
For example, to sort on the second comma-separated
field: >
    :sort /[^,]*,/
To sort on the text at virtual column 10 (thus
ignoring the difference between tabs and spaces):
    :sort /.*\%10v/
To sort on the first number in the line, no matter
what is in front of it:
    :sort /.\{-}\ze\d/
(Explanation: ".\{-}" matches any text, "\ze" sets the
end of the match and \d matches a digit.)

Sort within a pattern

With [r] sorting is done on the matching {pattern}
instead of skipping past it as described above.
For example, to sort on only the first three letters
of each line: >
    :sort /\a\a\a/ r

Reverse selected lines

Super User reverse selected lines

Select the paragraph and use the GNU tac command:

:'<,'>!tac`

To reverse the order of lines in a paragraph, you can use vip to select the current paragraph, followed by ! which automatically inserts :'<,'>! followed by tac. In short what you end up tipping to reverse the current paragraph is vip!tac.

Edit zip files

It’s possible to edit text files inside a zip archive with vim. Open the file as such:

vim file.zip

Align columns

The tabular plugin provides a Tabular command which can be abbreviated to :Tab. To align a latex table with the tabular package. Select a few lines, then press:

:'<,'>Tab /&

Align tab separated text in the current buffer (to view tsv files generated from data frames by NVim-R for example):

:Tab /\t

Or enter CTRL + V and press the TAB key for a literal tab.

To have numbers right aligned

:Tab /\t/r0

Markdown table

Similarly to align a markdown table, select a few lines, then call:

:'<,'>Tab /|

For more, see help tabular.

Undo redo

u: undo last change (can be repeated to undo preceding commands)
Ctrl-R: Redo changes which were undone (undo the undos). 
Compare to '.' to repeat a previous change, at the current cursor position.
Ctrl-R will redo a previously undone change, wherever the change occurred. 

Replace characters

Vim help on search and replace :help :s

[range]s[ubstitute]/{pattern}/{string}/[flags] [count] For each line in [range] replace a match of {pattern} with {string}.

For example find each occurrence of ‘red’ (in the current line only), and replace it with ‘green’:

:s/red/green/g

The s command means “substitute”. The g means “greedy”, it will replace all occurrences of the word on a line (not just the first occurrence).

When text is visually selected, press : to enter a command. The command line will automatically enter the range:

:'<,'>

Then you can enter a replacement command such as s/red/green/g to replace each occurence of “red” with “green” in all lines of the visual selection. The command will appear as:

:'<,'>s/red/green/g

Find each occurrence of ‘red’ in all lines (%s), and replace it with ‘green’.

:%s/red/green/g 

Find each occurence of foo but don’t perform the replacement, only count the number of occurences

:%s/foo/bar/n

To replace by a new line character, use \r instead of \n. For example to insert a new line after each comma in a selection:

:'<,'>s/,/,\r/g

To replace double line breaks by a single line brake

:%s/\n\n/\r/g

You can use replacement to remove text. For example to remove the last 2 characters of each line in a selection :

:'<,'>s/..$//

In case you have slashes in the pattern, you can use another separator such as #

:%s#/path/to/file#/new/path#g

See also:

Abbreviations and boilerplate code

Add a read counter item to a list of papers to read

iabbrev azer - {1}

Collection

See :help collection: “A collection is a sequence of characters enclosed in brackets.”

Example     matches ~
[xyz]       any 'x', 'y' or 'z'
[^xyz]"     anything but 'x', 'y' and 'z'
[a-zA-Z]$   any alphabetic character at the end of a line

For example to replace all characters but the pipe (to create a separation in a markdown table):

:'<,'>s/[^\|]/-/g

Confirm replacement

Find and replace with confirmation

:%s/old/new/gc 

Press y or n to confirm each replacement individually.

Convert to lower-case

Switching case of characters:

Toggle case "HellO" to "hELLo" with g~ then a movement.
Uppercase "HellO" to "HELLO" with gU then a movement.
Lowercase "HellO" to "hello" with gu then a movement.

For example to convert to lower case from the cursor to the end of the line:

gu$

To change the current line from upper to lower case:

guu

Grouping and back references

http://vimregex.com/ Grouping and Backreferences

“ou can group parts of the pattern expression enclosing them with "\(" and "\)" and refer to them inside the replacement pattern by their special number \1, \2 … \9. Typical example is swapping first two words of the line:

s:\(\w\+\)\(\s\+\)\(\w\+\):\3\2\1:

” where \1 holds the first word, \2 - any number of spaces or tabs in between and \3 - the second word. How to decide what number holds what pair of () ? - count opening "\(" from the left. ”

Keep only quoted strings

A simpler version in the case of character strings only

:'<,'>s/.*\(".*"\).*/\1/g
# Paste ready version
s/.*\(".*"\).*/\1/g

Suggestion and explanation by Chat GPT

:'<,'>s/.*\("\([^"]\+\)"\).*/\1/g

Explanation:

  • .* Matches any character zero or more times.
  • \("([^"]\+)"\) This is the capturing group for the quoted string. It captures anything between quotes and stores it in \1.
  • .* Matches any character zero or more times.
  • \1 This replaces the entire line with just the first capturing group, which is your quoted string.

HTML markup

Remove html tags, not the content

yitvatp

Markdown fixes

Several search and replace patterns to fix text copied from web pages or pdf files into markdown.

Place quotes around variables that contain a dollar sign (otherwise interpreted as a formula start in markdown):

:'<,'>s/\(\w*\$\)/`\1`/g

Remove hyphenation at the end of lines in a paragraph

:'<,'>s/\(\i\)- /\1/g

I put this into a command in my  .vimrc

command! -range=% Hyphen <line1>,<line2>s/\(\i\)- /\1/g

TODO: “the 30- year average” should not be replace but only by a space.

Regex patterns

To place quotes around variables that contain a dollar sign (otherwise interpreted as a formula start in markdown):

:'<,'>s/\(\w*\$\)/`\1`/g

add quotes at the start and end of each line

:%s/^\(.*\)$/"\1"/

s/regex/replace/ is vim command for search n replace. % makes it apply throughout the file ^ and $ denotes start and end of the line respectively. (.*) captures everything in between. ( and ) needs to be escaped in vim regexes. \1 puts the captured content between two quotes.

Remove bracketed references from text copied from Wikipedia.

:'<,'>s/\[[0-9]\+\]//g

Character classes

See also patterns below.

See :help character-classes for a list of classes accepted in Vim with their equivalent regex pattern, for example \w is equivalent to [0-9A-Za-z_]. Replace all word characters by a dash (to create a markdown table division see also collection below)

:'<,'>s/\w/-/g

Note that this only works with ASCII characters and doesn’t work with accentuated characters. For example smöl gets replaced by --ö-. To replace all identifier characters, use

:'<,'>s/\i/-/g

And then smöl gets replaced by ----.

Numbers

Insert Markdown title marker # before a number at the beginning of a line

%s/^\(\d.\)/# \1/g

Note \0 matches the hole pattern. Use backslash-escaped parenthesis to match a particular pattern. \d matches any digit.

Remove bracketed references from text copied from Wikipedia.

:'<,'>s/\[[0-9]\+\]//g

Remove all numbers in a list of authors

:'<,'>s/\d//g

Or

Replace this or that with a dot

:%s/this\|that/./g

Replace opening or closing curly braces by two curly braces

:'<,'>s/{/{{/g | s/}/}}/g

Replace list items

Replace simple list items with a curly braces counter (to count the number of times I want to read a publication or a paper). I have created a shortcut for this substitution.

:'<,'>s/\n- /\r- {1} /g

Replace spaces and new lines

Vim wiki Remove unwanted spaces:

In a search, finds white space (a space or a tab), and + finds one or more occurrences. Command to replace repeated white spaces by a single white space in a selection:

:'<,'>s/\s\+/ /g

SO vim regex replace multiple consecutive spaces with only one space proposes multiple other solutions, this one derived from Aristotle’s answer keeps indentation white spaces at the beginning of the line:

:'<,'>s/[^\s]\zs\s\+/ /g

Remove all beginnings of line. :%s//, /g replace all end of line by comma + space. This cleans an html list of species for inclusion in a text.

 %s/option value=".*"//g 

This pattern replaces one or more white spaces with a pipe, to create markdown tables:

:'<,'>s/\s\+/|/g

This pattern removes spaces at the end of the line:

:'<,'>s/\s*$//g

Visual selection

To search and replace in a visual selection, select an area then press :. The line will automatically begin with :'<,'>, you can then enter the patterns.

:'<,'>s/search/replace/g

For a vertical selection, this doesn’t work automatically and you have to use

:'<,'>s/\%Vsearch/replace/g

To replace a visual selection by inserting new text at the keyboard in insert mode, use c for change:

c

Copy, cut and paste

Copy

yy            The current line
yiw           The current word
ye            To the end of the current word
yip           The current paragraph
yG            To the end of the document

Paste with P (before) or p (after) the cursor.

Copy just one character

vy

Copy and paste in visual mode with the following instructions:

Position the cursor where you want to begin cutting.
Press v (or upper case V if you want to cut whole lines).
Move the cursor to the end of what you want to cut.
Press d to cut or y to yank (copy into the `"0` register).
Move to where you would like to paste.
Press P to paste before the cursor, or p to paste after. 

Copy to a system register (to be used by other programs)

"+yy
"+yip

See also the section on registers below and :help "+ for more details on system registers.

Paste the current line many times

Press Y6p to copy the following line 6 times

- example

Paste from the system register

When pasting from the system register i.e. with Ctrl+Shift+V you need to prevent auto indent otherwise vim will mess with the indentation. This can be solved with bracketed paste, see further down below.

As explained in Paste without autoindent You can either read from the shell with:

:r! cat 

And then paste CTRL + SHIFT + V the content, and CTRL+D. Also works over SSH.

Or use

:set paste
:set nopaste

Set up a shortcut to toggle paste mode on and off with:

set pastetoggle=<F3>

Note: I don’t use paste toggle any more, bracketed paste works well.

Bracketed paste

Enable bracketed paste in a session

bind 'set enable-bracketed-paste on'    

Registers

How to use vim registers

” Registers in Vim let you run actions or commands on text stored within them. To access a register, you type “a before a command, where a is the name of a register. If you want to copy the current line into register k, you can type

"kyy

Or you can append to a register by using a capital letter

"Kyy

You can then move through the document and paste it elsewhere using

"kp

To display the content of all registers:

:registers

For example yank the word “yank”, delete the word “delete” and copy the word “system” outside of vim in any program will give you the following registers:

:registers
--- Registers ---
""   delete
"0   yank
"-   delete
"*   system
"+   system
".   ^@yank^@delete^@

To clean vim registers as explained on a SO answer, enter this at the vim prompt:

for i in range(34,122) | silent! call setreg(nr2char(i), []) | endfor

Replace a word

How can I do a change word in vim using the current paste buffer

Select the current word, then select the word to replace and paste

ye
vep

Or select the current word, then paste and delete the word to replace

ye
Plde

Note this works only for one replacement because the yank register is then replaced with the deleted word.

A single character

Copy a single character at the cursor position

vy
xu

Copy a character before the cursor position

Xu

Cut a single character, then paste it later

x
p

From a Stack Exchange question on how to copy a single character in vim

Indentation

Indentation replaced by spaces, add this to the ~/.vimrc file

set tabstop=4
set expandtab
set softtabstop=4
set shiftwidth=4
filetype indent on 

More details on vim indentation in the python wiki. In particular the page How to stop auto indentation explains how to display indentation setting for the current file type:

:verbose set ai? cin? cink? cino? si? inde? indk?

Save files

Save the current file

:w

Rename a file, save as

Save under a new name (save as) and edit that file

:sav
:saveas

SO save as a new file and continue editing the original one

To move or rename a file within the vim file explorer:

R

Autosave

Wrap lines, auto line break

Thoughtbot.com Wrap existing block of text to 80 characters:

:set textwidth=80

Apply automatically to markdown files, by adding this to .vimrc

au BufRead,BufNewFile *.md setlocal textwidth=80

To format the text, select it with v and up or down movements, and press

gq

Disable auto wrap

To disable auto wrapping, call

:set formatoptions=cq

SO answer on how to disable auto wrapping.

Select and visual mode

Vim documentation

:help visual-use

Difference between visual and select mode

Various ways to select text in visual mode

vt<char> - till before a given character
vf<char> - till a given character

Select the current paragraph:

vip

Select the current word:

viw

Select what is in the current parenthesis block

vi(

Select what is inside the current quote block

vi"

Select the current line

V

These selection methods can also be used to delete diw and yank yiw.

Enter commands, save and quit

To enter edit mode:

i

To enter command mode:

escape

To exit vim, go in command mode and enter the following command:

:q

To exit without saving the content of the file:

:q!

To save the content of the file:

:w

If you accidentally press CTRL+S the terminal will hang Press CTRL+Q to regain control. See also Ctrl-s hang terminal emulator? which provides a workaround: entering stty -ixon in .bashrc.

To save content and exit:

:wq

Email with Mutt

See also the [debian.html] page. The Arch Linux wiki page on Mutt has a section explaining how to set it up with vim.

Help

:help - vim help
:help commandname - help on a particular command
:h commandname - help on a particular command
CTRL+] - jump to a highlighted topic. I remapped it to `ctrl %`.
CTRL+T - jump backwards

HTML version of the Vim help pages kept up-to-date automatically from the Vim source repository.

Messages

Did you see warning messages but they disappeared before you have had time to read them? Type the command |:messages| in Normal mode to see them again. (copied from nvim-r help)

Insert

Current file name

Insert the current file name in VIM In insert mode press:

<c-r>%

In normal mode:

:r! echo %

Content of another file

In normal mode, insert the content of another file:

:read /tmp/newdir/file1.txt

Insert the content of a file from the network:

:Nread https://www.wikipedia.org/

For more, see :help Nread.

Date or time

Vim wiki insert date or time

I added the following command to my .vimrc:

command! Date put =strftime('%Y-%m-%d')

Multiple files, buffers and windows

Buffers

:e filename - edit another file 
:ls         - show current buffers
:b 2        - open buffer #2 in this window
:b filename - open buffer #filename in this window
:bd         - close the current buffer (! to forget changes)
:bd filename -close a buffer by name 

Reload the file in the current buffer:

:e

Quickfix window

Open the quickfix window with:

:copen

The result of some search operation seach as grep can be displayed in the quick fix window.

Tabs should be called workspaces

Why do vim experts prefer buffers over tabs? > ““Vim experts” don’t prefer buffers over tabs: they use buffers as the file > proxies they are and tab pages as the workspaces they are. Buffers and tab > pages have different purposes”

Open a file in a new tab

:tabnew {file}

Move to the next tab

gt

Move to the previous tab

gT

Open the file under the cursor in a new tab

CTRL-W gf   Open a new tab page and edit the file name under the cursor.
        See |CTRL-W_gf|.

CTRL-W gF   Open a new tab page and edit the file name under the cursor
        and jump to the line number following the file name.
        See |CTRL-W_gF|.

See :help tabpage for more instructions.

Window split

:sp[lit] filename  - split window and load another file
:10sp - specify the split height with a number
:vs[plit] - same but split vertically  
ctrl-w up arrow - move cursor up a window
ctrl-w ctrl-w   - move cursor to another window (cycle)
ctrl-w_         - maximize current window
ctrl-w=         - make all equal size
CTRL+z - suspend the process and get back to the shell
fg - get back to vim

Easier split navigations

nnoremap <C-J> <C-W><C-J>
nnoremap <C-K> <C-W><C-K>
nnoremap <C-L> <C-W><C-L>
nnoremap <C-H> <C-W><C-H> 

Natural split opening

set splitbelow
set splitright

Open an existing buffer (from the buffer list) in a new split

:sb buffername

For a vertical split

:vert sb buffername

Open vim with two files in two splits or more

ViM Stack exchange Open 2 files in 2 horizontal splits

vim -o file1.md file2.md

Limit the number of splits

vim -o2 *.md

Open files in vertical splits

vim -O file1.md file2.md

Split resize

Set current window height to 10 lines

res 10

Set current window width to 100 characters

vertical res 100

See :help resize for more commands. There are many possible key combinations to resize the window.

:res[ize] [N]
CTRL-W CTRL-_                   *CTRL-W_CTRL-_* *CTRL-W__*
CTRL-W _    Set current window height to N (default: highest possible).
z{nr}<CR>   Set current window height to {nr}.

Change the height of the current window by increments of 10:

:res +10

Change the with of the current window by increments of 10:

:vert res +10

Set the height of the terminal buffer to 10 lines

:set termwinsize=10x0

Split zoom in and out

zoom windows in vim

c-w-| to have window take over (if using vsplits). 
c-w-_ for horizontal splits
c-w-= to restore. 

Vim and Tmux

See the bash page for the tmux side of the configuration.

I use the vim-tmux-navigator

It doesn’t work in a terminal buffer because of conflicts with fuzzy file search. issue 172

vim-tmux-navigator to use tmux prefix instead of C-[hjkl]

busnag.com tmux and vim > ” like many vim users, I edited my .vimrc to simplify split navigation, so > that I can jump between vim splits using ctrl-j, ctrl-k, etc.

reddit python workflow with terminal using tmux > “Finally, I have Ctrl+[hjkl] setup such that I can navigate seamlessly between vim and tmux panes.”

NeoVim

Plugins

Plugins are mentioned in diverse section of this document. This section is mostly to list plugins I used and potentially interesting plugins.

Display plugins I currently use with vundle:

:PluginList

Copy of the list from my .vimrc:

" Colour themes for Vim
Plugin 'morhetz/gruvbox'
Plugin 'nanotech/jellybeans.vim'
" Code structure i.e. table of content of classes, methods and functions
Plugin 'yegappan/taglist'
" Git interface 
Plugin 'tpope/vim-fugitive'
" Latex editing
Plugin 'vim-latex/vim-latex'
" Markdown toc navigation
Plugin 'godlygeek/tabular'
Plugin 'plasticboy/vim-markdown'
" Python autocompletion 
Plugin 'davidhalter/jedi-vim'
" Python linter
Plugin 'dense-analysis/ale' 
" R programming
Plugin 'jalvesaq/Nvim-R'

I also use a spell checker.

Other plugins installed in the default vim repo:

:r ! ls ~/.vim/pack/plugins/start/
indentpython.vim
pytest.vim
vim-slime
vim-tmux-navigator

Potentially useful plugins

  • fugitive git integration
  • Quick fix preview
  • Fuzzy search
  • fzf command line fuzzy finder fzf
  • File explorer
    • or simply use the native vim explorer :Explore
  • Minibufexplorer and SO post on alternatives to minibufexplorer
  • Vimtex vim plugin for editing LaTeX files.
  • distribution spf13 probably not recommended but the home page contains a list of interesting plugins.
  • See also the section programming with vim below for language specific plugins.

Create a plugin

I’m trying to extract a table of content functionality from a plugin that does many other things I don’t need.

I extracted the function into a plugin called markdown-toc-toc I placed the plugin in ~/.vim/pack/plugins/start/markdown-toc-toc and this fixes my issue. I now have both Nvim-R autocompletion and syntax highlight working correctly in R markdown chunks as well as a table of content for the markdown titles. Later on, I moved to the Voom plugin for the table of content.

Deactivate a plugin

To temporarily deactivate a plugin in a session.

Detect slow plugins

How to see which plugins are making Vim slow?

“You can use built-in profiling support: after launching vim do”

:profile start profile.log
:profile func *
:profile file *
" At this point do slow actions
:profile pause
:noautocmd qall!

“If you’re having problems with screen update operations (^L, scrolling, etc) being slow, your problem may be an inefficient syntax highlighting file. You can test this by temporarily disabling syntax highlighting”

:syn off

To profile the syntax file

Open a file that causes syntax highlighting performance issues.
Run :syntime on to start profiling.
Scroll through the file a bit.
Run :syntime report to generate a report. The patterns listed first in the report are the ones which took the most time to process.

The matchparen plugin seemed to be slow on large markdown documents. It’s part of the vim distribution and loaded by default. vi.stackexchange matchpairs makes vim slow. But it was called by the Pandoc syntax highlight file.

Install plugins with vim’s built-in plugin support

Install slime with Vim’s built-in package support (since Vim 7.4.1528):

 mkdir -p ~/.vim/pack/plugins/start
 cd ~/.vim/pack/plugins/start
 git clone https://github.com/jpalardy/vim-slime.git

Install plugins with Vundle

Install all plugins configured in your .vimrc.

:PluginInstall

Update the configured plugins. Press ‘u’ after updates to see the change log.

:PluginInstall!   " NOTE: bang(!)
# or
:PluginUpdate

Since there is a built-in plugin support, maybe I don’t need Vundle after all?

Tell Vundle to manage plugins in your .vimrc

Edit your .vimrc and add the following at the beginning

set nocompatible              " be iMproved, required
filetype off                  " required

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" alternatively, pass a path where Vundle should install plugins
"call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'
" Navigate markdown toc
Plugin 'godlygeek/tabular'
Plugin 'plasticboy/vim-markdown'
Plugin 'tpope/vim-fugitive'
Plugin 'jpalardy/vim-slime'

" All of your Plugins must be added before the following line
call vundle#end()            " required
filetype plugin indent on    " required
" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append `!` to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line

Programming

Latex editing

vim Latex

vim-latex the one I used first.

  • Was complaining about my makefile, that it didn’t include a dvi section
  • Was creating nice taglist but with duplicated tags.

Vimtex

vimtex is more recent compared to vim-latex

  • Completion uses omni completion, see :help compl-omni with CTRL-X CTRL-O
  • doesn’t complain about my minimalistic makefile
  • doesn’t add anything to the taglist (maybe I should use gutentag?) but there is a table of content buffer.

Usage as explained in ̀:help vimtex-default-mappings:

———————————————————————~ LHS RHS MODE~ ———————————————————————~ lv |(vimtex-view)| n lr |(vimtex-reverse-search)| n ll |(vimtex-compile)| n ———————————————————————~

I mapped <localleader> to ;.

Display a table of content:

:VimtexTocOpen
:VimtexTocToggle

Define a shorter command name Toc, by placing this in the .vimrc

au BufRead,BufNewFile *.tex command! Toc VimtexTocOpen

I first ran into this error when viewing git diffs or when jumping back to the tex file with Ctrl-O

Error detected while processing BufRead Autocommands for "*.tex":
E174: Command already exists: add ! to replace it: Toc VimtexTocOpen

Because I had the autocommand defined this way:

au BufRead,BufNewFile *.tex command Toc VimtexTocOpen

Compile

:VimtexCompile

Install prerequisite to view pdf files with forward (from vim to the pdf viewer) and backward (from the pdf viewer to vim) search. Note: Forward and backward search are not available for evince issue 179.

sudo apt install zathura
sudo apt install xdotool

This bug report pushed me to learn about xdotool and xprop.

There was a issue with the focus not moving to the zathura viewer. I reported it as issue #1719. The first step was to add client server support to vim. I asked a question on how to install vim with clientserver support. But the issue remained even with client server enabled in vim.

The second step was related to the fact that Debian 10 Buster uses wayland as a window manager. To force the use of x11 for zathura, in debian a zathura wrapper script containing:

#!/usr/bin/bash
GDK_BACKEND=x11 /usr/bin/zathura "$@"

Can be placed under the default user bin located at ~/.local/bin. This is one of the first element of the $PATH environment variable.

Python programming

Plugins * Python mode * Jedi it’s incompatible with python mode (according to the readme) * more explanations in the Jedi section below * vim ipython * [vim-test] see also the tests section below.

Blog posts

Reddit python workflow with terminal using tmux

“I run my scripts using

ipython -i script.py

That way I drop to an ipython shell whenever it breaks or finishes running. I also insert

from ipython import embed; embed();

Instead of using pdb. Its really neat.”

Ale Linter

I use the ALE linter to check the quality of python code.

To copy code it’s preferable to deactivate the 2 characters columns used by ale as explained in Is it possible to disable the column on the left that is created by ALE?

:set signcolumn=no

The 2 characters column can later be shown again with

:set signcolumn=yes

To temporarily disable ALE in a buffer:

:let b:ale_enabled = 0

To enable it:

:let b:ale_enabled = 1

For the python options, see:

:h ale-python-options

I’ve added this option to my .vimrc to show which linter is complaining

let g:ale_echo_msg_format = '[%linter%] %s'

The linters I see most in python code are pylint and flake8.

Pylint complains about variable names that are too short

See the python page for the configuration details of the linters.

Turn off virtual text (added to .vimrc)

let g:ale_virtualtext_cursor = 0

Flake 8

Example exception file .flake8 at the root of the git repository

[flake8]
ignore = F841, E501, W503, E203

Jedi vim

Jedi Installation required enabling python mode in vim, available inside this Debian package:

sudo apt install vim-nox

Autocomplete is turned on to complete a word, press:

Ctrl+Space

To cycle through proposition you can use Ctrl+space again or:

Ctrl+P
Ctrl+N

Enter for example a module name, then use Ctrl+N and Ctrl+P to choose among the objects and functions in that module.

Show the help of a function or object:

K

Jump to definition:

<leader>d

I remapped the <leader> key to , in my .vimrc

:let mapleader = ","

See above section on navigation, you can use Ctrl-O to jump back and Ctrl-I to jump forward.

Refactor with jedi#rename()

To refactor all occurrences of a variable in a file, move to the object you want to rename, then

:call jedi#rename()

There is a default shortcut <leader>r for this but it is deactivated on my machine for some reason. Not a big problem since I don’t use refactor often. Also I prefer not to call this shortcut by mistake.

The advantage of jedi#rename() over a simple :%s/old/new/g is that it will only replace python objects, if you have them mentioned in comments, it will not replace those.

See also my refactor with git grep and perl in the bash page.

Open files from traceback error messages

The goal is to open files at the line number specified in a python error trace back message.

Using Vim Dispatch to run pylint on the current script works correctly and returns a quick fix window with errors on the relevant lines:

:Dispatch pylint -f parseable %

Running the current script itself with ipython

:Dispatch ipython %
:Dispatch ipython3 ~/repos/eu_cbm/eu_cbm_hat/scripts/running/run_zz.py

Opens a small tmux pane at the bottom of the tmux window and starts the script. Upon completion, the output is available in a quickfix window. One issue is that the files cannot be opened with gF. File names in the quickfix window output are not parseable to jump to them. I get error messages of this form in the quick fix window:

    || hat/ZZ/0 - INFO - Saving final simulations results to disk.
|| ^[[0;31m---------------------------------------------------------------------------^[[0m
|| ^[[0;31mAttributeError^[[0m                            Traceback (most recent call last)
|| ^[[0;32m~/repos/eu_cbm/eu_cbm_hat/scripts/running/run_zz.py^[[0m in ^[[0;36m<module>^[[0;34m^[[0m
|| ^[[1;32m     20^[[0m ^[[0;31m# runner.country.base_year = 2020^[[0m^[[0;34m^[[0m^[[0;34m^[[0m^[[0;34m^[[0m^[[0m

Running it with python3 is better because I can actually open the file with gF, however still not at the correct line number

:Dispatch python3  %

Issue 299 with recommended settings

autocmd FileType python let b:dispatch = 'pylint -f parseable %'

Still doesn’t work for me, TODO: make a reproducible example and post on Vi stackexchange.

Other links

R programming

Nvim-R

Nvim-R supports knitr and mappings can be defined for example:

RSendChunk RDSendChunk

I mapped the local leader key to “;” by adding the following to my .vimrc:

let maplocalleader = ";"

Start R

  • Start R (default) ;rf

Sending code to R:

  • Chunk (cur, echo and down) ;ca
  • Chunk (cur) ;cc
  • Chunk (cur, echo) ;ce
  • Chunk (cur, down) ;cd
  • Chunk (from first to here) ;ch
  • Line ;l
  • Line (and down) ;d
  • Line (and write output as a comment) ;o
  • Selection ;ss
  • Selection (echo) ;se
  • Selection (evaluate and insert output in new tab) ;so
  • File ;aa
  • File (echo) ;ae
  • File (open .Rout) ;ao

Object browser

  • Open/Close the object browser ;ro
  • Expand (all lists) ;r=
  • Collapse (all lists) ;r-
  • Toggle (cur) Enter

On the code, when the cursor is on a data frame:

  • Names (cur) ;rn
  • Structure (cur) ;rt
  • View data.frame (cur) in new tab ;rv
  • View data.frame (cur) in horizontal split ;vs
  • View data.frame (cur) in vertical split ;vv
  • Selection (evaluate and insert output in new tab) ;so

Edit code

  • Toggle comment (line, sel) ;xx

Help on a function ;rh

Tags

To generate tags for R files contained in a project’s R/ subfolder, define the following bash function:

rtags() {
    Rscript -e "rtags(ofile = 'et'); nvimcom::etags2ctags('et', 'tags'); unlink('et')"  && cat tags
}

Usage:

cd ~/rp/eutradeflows/R  && rtags

The bash function above was inspired by NVimR’s :RBuildTags command. Alternatively, you can call the line starting with rtags above from within Vim with :RBuildTags. But this requires moving to the /R subfolder first and moving back to the project root after having created the tags:

R > setwd("R") # R command

:RBuildTags # VIM command

R > setwd("..") # R command

Display tag files currently seen by vim:

:set tags

Navigate tag files with CTRL+] (CTRL+ù on my setup).

https://stackoverflow.com/a/14465438/2641825

An NVim-R issue about displaying a nice list of tags for R functions.

I have added some of my packages to the tag files always seen by vim:

autocmd FileType r set tags+=~/rp/tradeharvester/R/tags,~/rp/eutradeflows/R/tags
autocmd FileType rmd set tags+=~/rp/tradeharvester/R/tags,~/rp/eutradeflows/R/tags

Setting up tags as explained in :help Nvim-R

You could, for example, download and unpack R’s source code, start R inside the ~/.cache/Nvim-R directory and do the following commands:

 rtags(path = "/path/to/R/source/code", recursive = TRUE, ofile = "RTAGS")
 etags2ctags("RTAGS", "Rtags")

Then, you would quit R and do the following command in the terminal emulator:

 ctags --languages=C,Fortran,Java,Tcl -R -f RsrcTags /path/to/R/source/code

Finally, you would put the following in your |vimrc|, optionally inside an |autocmd-group|:

 autocmd FileType r set tags+=~/.cache/Nvim-R/Rtags,~/.cache/Nvim-R/RsrcTags
 autocmd FileType rnoweb set tags+=~/.cache/Nvim-R/Rtags,~/.cache/Nvim-R/RsrcTags

Config example https://gist.github.com/tgirke/7a7c197b443243937f68c422e5471899

Knitr issue

Posted this to https://github.com/jalvesaq/Nvim-R/issues/509

One solution based on :help Nvim-R-key-bindings, is to use SendCmdToR as such:

:call g:SendCmdToR("setwd(opts_knit$get()$root.dir)")

I mapped this to <localleader>wd by editing my .vimrc as follows:

map <silent> <LocalLeader>wd  :call g:SendCmdToR("setwd(opts_knit$get()$root.dir)")<CR>

To use it, I run the setup chunk with <localleader>ca, then I call <localleader>wd.

Debugger

vi.stackexchange Python debugging vimpdb

Git fugitive

Once the fugitive plugin is installed the :G command can be used run any git command, such as:

:G status
:G pull 
:G log

The output of these command may appear in a vim buffer, or it may appear in a terminal, depending on whether or not fugitive has a special way to handle the output of git.

:G Summary buffer similar to git status

You can also call the command alone to open a fugitive summary buffer:

:G

Within this summary buffer many things can be done with mappings. Move to the next file and expand inline diffs:

i

Expand inline diffs of the file under the cursor :

>

Remove the inline diff of the file under the cursor.

<

Perform a horizontal diff on the file under the cursor.

dd

Perform a vertical diff on the file under the cursor.

dv

Stage (add) or unstage (reset) the file under the cursor:

a
-

Create a commit

cc

Discard the change under the cursor. This uses checkout or clean under the hood. A command is echoed that shows how to undo the change. Consult :messages to see it again. You can use this during a merge conflict do discard “our” changes (–theirs) in the “Unstaged” section or discard “their” changes (–ours) in the “Staged” section.

X

X discard changes

The powerful X command led me to loose a bunch of changes. A help hint in the message bar says to use the following to recover one file

:Gsplit art/music.md|Gread 124cdf331a4

I managed to recover that test files. How do I find out about the other files deleted previously?

cc commit

When committing markdown file I like to get a summary of the modified titles as the long part of the commit message. Search pattern to look for modified titles of level 2 and more in the diff part of the fugitive git summary buffer accessible after pressing i on a file name:

:g/+##

Git commands within vim

Blame the current file in a left side split

:G blame

Git log of the current file only

:G log %

Since the word diff provided by fugitive is not colourized, I created an alias to display a word diff

:Gwdiff

It’s defined in .vimrc as:

command! Gwdiff vert term git diff --word-diff

Slime to send code to a target terminal

vim slime > “Grab some text and send it to a target, most probably: GNU Screen, tmux or Vim Terminal”

Tmux is not the default, to use it you will have to add this line to your .vimrc:

let g:slime_target = "tmux"

Then add this to configure the sending of commands to a Read Eval Print Loop: in the general use case of vim in a split tmux window with a REPL in the other pane:

let g:slime_default_config = {"socket_name": "default", "target_pane": "{last}"}

Send command to a tmux pane running bash, python or R with:

Ctrl C

Python shell mappings

I created the shortcut ;w, ;l and ;p to emulate NvimR’s shortcut which send the current word, the current line or the current paragraph to the latest interactive shell (ipython)

autocmd FileType python nmap <buffer> <LocalLeader>w viw<Plug>SlimeRegionSend
autocmd FileType python nmap <LocalLeader>l <Plug>SlimeLineSend
autocmd FileType python nmap <LocalLeader>p <Plug>SlimeParagraphSend

IndentationError: unexpected indent

Excessive indentation issues can arrise when slime sends indented lines to the ipython console. For example after a function definition, such as def function_name(): ipython places the cursor at the indented place (4 spaces) and slime sends an additional 4 (or more spaces) to indent the line further. This creates an “IndentationError: unexpected indent”. This shouldn’t be done when slime is sending intput. Ipython’s auto indentation behaviour can be turned off by sending the following command to ipython:

%autoindent off

Syntax highlight

Turn off syntax highlight

syn off

Start Vim with syntax highlight turned off

vim -c 'syn off'

You can also specify a rule that vim should turn off syntax highlight for large files Stackoverflow question.

Concealing

Markdown

Use the shorthand version :set cole=0 to turn off concealing of markdown bold ** and italic * marks as well as the replacement of # Title to § Title. More explanations in How to prevent vim from hiding symbols in Markdown and JSON

:set cole=0

Or set the file type to text

:set ft=text

Tests

Vim Test Works with pytest and other testing suites for many languages. Test results appear in the quick fix window.

pytest vim Run pytest from within vim.

Pytest vim (not used)

I put the following options in the .vimrc

" Pytest
nmap <silent><Leader>f <Esc>:Pytest file<CR>
nmap <silent><Leader>c <Esc>:Pytest class<CR>
nmap <silent><Leader>m <Esc>:Pytest method<CR>

Vim test

Keyboard mapping defined in .vimrc:

nmap <silent> <leader>T :TestFile<CR>
nmap <silent> <leader>a :TestSuite<CR>

Define strategies to send the test output

let test#strategy = "make"
" let test#strategy = "dispatch"

Use :copen to display a quickfix window.

Terminal interaction

Bang commands

Use a Bang! to run a command directly, for example to see how many words are in the file, run:

:! wc %

To insert the word count directly in the file, run:

!! wc %

You can copy (y $) and paste a command in the vim command line with CTRL + R + ".

Insert text from a specified file into the current buffer:

:r textfile

You can also read in the output of shell applications. For example, if you wanted to include a list of files from a specific directory, you could include them using a read command:

:r ! ls -1 /home/user/directory

Or simply using the double bang

 !! ls

Shell

Working with external commands explains how to start a shell:

:shell

Then exit the shell normally with exit.

See also terminal buffer below.

Terminal buffer

You can start a terminal inside a vim split by entering the command:

:terminal

To enter the normal mode in a terminal buffer:

CTRL+W+N

Reddit does anybody use terminal instead of tmux and a normal terminal? Some users prefer tmux panes and windows, others prefer vim terminal. I have not used vim terminal buffers enough to know how to use them properly. For example slime is also working with vim’s terminal

To start a vertical terminal:

:vert term

Open a terminal in a new tab:

:tab term

Start a make action:

:term make

Start ipython3:

:vert term ipython3

Change the terminal window size to be 4 lines high (works for all subsequent opening of a terminal :term)

:set termwinsize=4x
:set tws=4x

Change the size of the current terminal

:res 10

Tools

Count words

Word coung: > To count the number of words in the current buffer, press g then Ctrl-g. To > count the number of words in a block, select the block (for example, type V5j > to select 6 lines) or vip to select the current paragraph and again press

g
Ctrl-g

This will also display the character count.

Macros

Vim wiki Macros

qn  start recording to register n
...     your complex series of commands
q   stop recording
@n  execute your macro
@@  execute your macro again 

“Suppose you have a macro which operates on the text in a single line. You can run the macro on each line in a visual selection in a single operation: Visually select some lines (for example, type vip to select the current paragraph). Type :normal @q to run the macro from register q on each line.”

Macro to add a new line below each line

qq     " start recording to register q (you could use any register from a to z)
o      " insert an empty line below cursor
<Esc>  " switch to normal mode
jjj    " move the cursor 3 lines downward
q      " stop recording

Then just move to the start line and type to execute your macro 1000 times.

Spell check

How to configure vim spellcheck to use two languages To use the spellcheck for two languages, add this to your ~/.vimrc:

set spell spelllang=en_gb,fr

To use the spellcheck only temporary for an additional language (italian in this case):

set spell spelllang=it
set spell spelllang=de

This might require installing addition Debian packages on the system.

On the first use, vim may give a warning that some word lists are missing. How to make vim download missing word lists To solve this issue, turn spell check off

:set nospell 

Turn spell check on

:set spell

Then vim will offer to download the missing dictionaries.

Set spell check only in the local buffer:

:setlocal spell spelllang=en_gb   

Find alternative for highlighted word:

z=

How to make vim spell check remember a word Mark word as correct, this creates a spell file under /home/user/.vim/spell:

zg 

Mark word as incorrect

zw

Vim diff

View differences between file1 and file2 (vim documentation)

vimdiff file1 file2

Blogs and resources

This page is the continuation of my 2014 blog post on Vim commands.

Other editors

const salute = ‘I salute you oh Mighty Warrior’ You type ci’Hi! and it becomes: const salute = ‘Hi!’

Learning vim

The history of vim

“The project I encountered in Kibaale is completely different. The foreigners who work there are volunteers, they have sponsors themselves to make it possible to live and work there. All the donations for children go to the project and are spent there. Also for staff and vehicles, but that’s local staff that then spend their money in the country, thus indirectly it helps others. And in the end seeing the children grow up, finish their studies and find a job is wonderful.”

“The original code for vi was written by Bill Joy in 1976, as the visual mode for a line editor called ex that Joy had written with Chuck Haley.[3] Bill Joy’s ex 1.1 was released as part of the first Berkeley Software Distribution (BSD) Unix release in March 1978. It was not until version 2.0 of ex, released as part of Second BSD in May 1979 that the editor was installed under the name”vi” (which took users straight into ex’s visual mode),[4] and the name by which it is known today. […] On the free software process

  • Vim is based on vi, itself based on the ex editor

“The core ex commands which relate to search and replace are essential to vi. For instance, the ex command :%s/XXX/YYY/g replaces every instance of XXX with YYY, and works in vi too. The % means every line in the file. The ‘g’ stands for global and means replace every instance on every line (if it was not specified, then only the first instance on each line would be replaced).”