vim
vim
The Ubiquitous Text Editor
(source: vim.org)
VK / 2020-09-17 (rev. )
Introduction
ubiquitous /juːˈbɪkwɪtəs/: present, appearing, or found everywhere
Vim is a highly configurable text editor built to make creating and changing any kind of text very efficient. It is included as “vi” with most UNIX systems and with Apple OS X. (vim.org)
- first released 1991 (Vi IMproved, based on
vi
from 1976…) - written in C, charityware with GPL-compatible licensing
- Most popular development environments #5 in Stack Overflow’s 2019 survey (2nd for SRE/DevOps)
- probably also installed to your router and Smart TV…
- while not as featureful as Emacs, has lots of features built-in, and provides very extensible platform for custom plugins & mods
- by default almost everything is disabled
- extremely lightweight compared to newer node.js based massive text editor frameworks
Maybe too lightweight by default?
By default vim is maybe even too simplified, and it has quite steep learning curve for newcomers. It can be improved also for more experienced users, as there is lots of tasks to be automated, new keybindings to be added etc.
Maybe we can add some good features that modern editor should have, to make vim much more usable, while keeping its low resource usage?
So, let’s see what we can do with some modifications.
Notes
Examples are based on the out-of-box experience (OOBE) on current Debian unstable/testing (future bullseye release). Some of the latter examples might depend on the customizations done on previous slides.
$ vim --version |head -n1
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled May 12 2020 02:37:13)
vim
is preinstalled on many systems, but you can install it easily, eg.
# Debian/Ubuntu and derivatives
sudo apt-get install vim
# Centos/Fedora/RHEL and derivatives
sudo dnf install vim
You can optionally use Docker for testing, docker run -it
ypcs/tools:vim-latest
has all tools and configs already installed for you.
First start using default settings (no file opened)
Editing a file using default settings
Editing a file using some customizations
Editing a file using lots of customizations (including: git status, syntax checking)
Different vim modes
In vim
there is four different operating modes, and this is something that
might confuse newcomers. Current mode isn’t even shown by default.
Mode | Description | How to enter |
---|---|---|
NORMAL | Default, navigate inside a file. (“Read mode”) | Esc |
INSERT | Edit/write: insert at cursor, at beginning of line | iI |
insert after cursor, at end of line | aA |
|
start new line before/after current | oO |
|
REPLACE | Just replace everything as you type | R |
VISUAL | Select characters / lines / blocks | vV^V |
You can switch from other modes to normal usually by hitting Esc
.
Keyboard is your tool, but if you really want, :set mouse=a
is there for
some features…
vim command structure
vim
commands consist of verb and noun. Commands can have a multiplier and
commands can be repeated and chained.
Some examples:
i
insert (verb) (at cursor) (noun)d$
delete (verb) (to) end of line (noun)20k
20 times move up (verb) (a line) (noun)/myword
search (verb)myword
(noun)jj
(twice) move down (verb) (a line) (noun)j2kl
move down, then two times up, and one time rightgv
start visual mode at previous position
More about vim
keys follows…
To quit vim…
To quit: you must be in normal mode (hit Esc
) and then
:q
quit:q!
quit, discard changes:wq
write changes and quit (:x
write if there is changes, and quit):wq!
write changes (with force) and quit:qa
quit all (tabs, split buffers etc.):cq
quit, discard changes and use exit code 1
Also
:help
for more tips
Stack Overflow, How to exit Vim, answer with +5100 votes…
There is some alternative ways to achieve somewhat similar results…
Moving in the document
You must be in other mode than insert or replace.
h
move one character left,l
move one character rightw
move one word right (to begin),e
move one word right (to end),b
move one word leftj
move one line down,k
move one line up(
move one sentence left,)
move one sentence right{
move one paragraph left,}
move one paragraph right%
jump to next matching item, parenthesis/word
search forword
,n
next match,d/word
search and delete:
move to lineg;
move to last edit
Editing the document
How to manipulate text. These apply either to current position of your line, or in visual mode your current selection.
y
yank / copydw
delete / cut a word,dd
delete / cut a line,c
cut rest of the linep
pasteu
undo<
dedent>
indent.
repeat previous command
Basic configuration
You can either configure vim via ~/.vimrc
or by configuring at runtime. Only
changes made to ~/.vimrc
will persist.
If you set runtime options, you need to switch to normal
mode (usually hit
Esc
to exit other modes), and prefix the option with colon (:
).
Eg. :set showmode
to show current operating mode (caveat: normal
doesn’t
still show anything…)
Essential configuration
Some basic configuration to make life with vim
much nicer.
" Show current mode
set showmode
" Set terminal title to current filename
set title
" Enable syntax highlighting
syntax on
" Always show ruler (current row/column etc.)
set ruler
" Security: Disable modelines
set modelines=0
Full example: https://ypcs.fi/misc/code/vim/vimrc.txt
… essentials, more
Some extra tuning for the basics.
" Wrap long lines
set wrap
" Show line numbering
set number
" Set default encoding
set encoding=utf8
" Wait 300ms until triggering plugins after text input stops
set updatetime=300
" Modify how backspace works (don't be as restrictive as by default)
set backspace=indent,eol,start
Pick up where we left off
You edit file, close the editor, do some tests maybe, and then decide that you need to modify same code again. What if vim could remember the last place you were in a file?
" Return to last edit position when opening files
autocmd BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g`\"" | endif
" Remember info about open buffers on close
set viminfo^=%
" Source: <https://stackoverflow.com/a/23036077>
"set viminfo=%,<800,'10,/50,:100,h,f0,n~/.vim/cache/.viminfo
" | | | | | | | + viminfo file path
" | | | | | | + file marks 0-9,A-Z 0=NOT stored
" | | | | | + disable 'hlsearch' loading viminfo
" | | | | + command-line history saved
" | | | + search history saved
" | | + files marks saved
" | + lines saved each register (old name for <, vi6.2)
" + save/restore buffer list
Leader key
vim
has special key, often denoted as <Leader>
in configuration files. You
can think this as custom namespace for your own keybindings, ie. some key that
you press before actual command key(s). By default this is [
, but that’s
pretty awful key combination on non-US keyboard.
So, let’s remap that to ,
.
" Map <Leader> key to , (default \),
" think this as a custom namespace for keybindings
let mapleader=","
Indentation
Quite often spaces are preferred over tabs, and you’d like to have SOME intelligence in how your editor handles indentation. Yet again, defaults need some tuning.
" Convert tabs to spaces
set expandtab
" Use 4 spaces as default indentation
set shiftwidth=4
" Set tabstop to 4 spaces
set tabstop=4
" Use same indent as previous line
set autoindent
" Enable smart indent (syntax/filetype specific)
set smartindent
" Fix invalid indents (round to nearest)
set shiftround
Search
By default there is no highlighting, search is case-sensitive and you can’t append to current search terms. Let’s change that.
" Highlight search terms
set hlsearch
" Ignore case when searching
set ignorecase
" ... but if pattern contains uppercase letters,
" then consider it case-insensitive
set smartcase
" Use incremental searching (move the highlight as you
" type in new characters to search)
set incsearch
Abbreviations
Good text editor is able to help you write correctly, eg. converts abbreviations to words, and maybe fixes some typos.
" Some common terms
abbr IANAL I am not a lawyer, but ...
abbr AFAIK As far as I know
abbr CGI Common Gateway Interface
" Fix typos
abbr lunix Linux
abbr todo TODO
" Hackish, but you can e.g define code snippets
abbr pyclass class MyClass(object):<CR> def __init__(self, *args, **kwargs):<CR> pass
Extras: Unicode emojis 🏆
You can also misuse some features, eg. to have emojis autocompleted from
:markup:
using abbr
feature.
🦄 👹 🥴 💰 🏆 … because why not?
abbr :grinningface: 😀
abbr :grinningfacewithbigeyes: 😃
abbr :grinningfacewithsmilingeyes: 😄
abbr :beamingfacewithsmilingeyes: 😁
abbr :grinningsquintingface: 😆
abbr :grinningfacewithsweat: 😅
abbr :rollingonthefloorlaughing: 🤣
abbr :facewithtearsofjoy: 😂
abbr :slightlysmilingface: 🙂
abbr :upside-downface: 🙃
abbr :meltingface: 🫠
abbr :winkingface: 😉
abbr :smilingfacewithsmilingey[...]
Show trailing whitespace etc.
Sometimes you need to see if there is tabs, trailing whitespace or newlines in
our code. Let’s map <Leader>l
to show you these characters.
" Visualize trailing whitespace, tabs and newlines
set listchars=trail:·,tab:▸\ ,eol:¬
" Leader key + l = toggle showing whitespace/tab/newline
map <leader>l :set list!<CR>
I’m ready, let’s build
When you complete your changes, you often like to build…
:make build
… or just any command
:!mycustom_command --with-params
Of course these can be also mapped to eg. file save event,
autocmd BufWritePost *.py :!ls -lha
Look up for a function implementation with ctags
Using ctags
it’s pretty easy to do
code searches in vim
.
cd $REPOSITORY
ctags -R * [../thirdparty/wordpress-core]
vim myfile.php
Then, using our custom mappings, we create easy mapping for looking up current
word in ctags
dataset.
" ctags: jump to definition of current word with <leader>a
nnoremap <leader>a <C-]>
" generate ctags on file close
autocmd BufWritePost *.c,*.cpp,*.h,*.hh,*.php,*.py,*.js :execute 'silent !ctags . &' |redraw!
Now, while cursor is over some interesting function name, just hit <Leader>a
to see the implementation.
You can also look for specific function with :tag <searchterm>
.
Write with sudo
You opened a file, did some changes and then realized you don’t have permissions to write that file, you’d need to be root? No problem!
:w !sudo tee %
ie. write buffer (and pipe) output to sudo tee %
, where % points to current
filename
Miscellaneous
Some misc. commands
:sort
sort selected lines
See keymaps
:map
all:nmap
normal mode:imap
insert mode:vmap
visual mode
File explorer
:Explore
:Vexplore
:Sexplore
UI: tabs, split screen
Yes, vim
also supports tabs.
:tabedit path/to/file
opens a new file in tab:tabnext
move to next tab:tabprev
move to previous tab:help tab-page-commands
for more
and you can also split a screen to have multiple buffers visible simultaneously.
:vsplit
split screen vertically:split path/to/file
split screen horizontally, and open a file:help split
for more
Extend: Plugins, color schemes, …
If vim
is missing some feature or eg. syntax higlighting support for specific
language or filetype, it’s usually available as a plugin.
Also, if you don’t like the default colors, there is lots of color schemes/themes available too.
Plugins: Install
This focuses solely on plugins included in Debian repos, as like any software, you should first asses the security of the software before you install something, and I just don’t have time to. So, let’s use plugins that Debian project has reviewed.
Plugins we look here are included in these packages:
apt-get install vim-scripts vim-gitgutter vim-airline vim-syntastic vim-youcompleteme
In this case we depend on files that are already in the system, so we use symlinks to “install” these to our user. Eg.
mkdir -p ~/.vim/plugin
ln -s /usr/share/vim-scripts/plugin/{vcscommand,vcsgit}.vim \
~/.vim/plugin/
Plugins: Version control integration
vim-scripts plugins: vcscommand.vim
, vcsgit.vim
So, you’d like to commit
, blame
and do other git stuff while editing file?
It’s possible.
Plugins: GnuPG
vim-scripts plugin: gnupg.vim
Automatically decrypt/encrypt files using GnuPG when opening/closing a file. No more need to decrypt, open editor, re-encrypt.
Plugins: Secure modelines
vim-scripts plugin: securemodelines.vim
Modelines are vim feature, in which some details about file formatting (indentation etc.) get stored in target file. Modelines look like this:
/* vim: set noai ts=4 sw=4: */
and you can quite often find them in source code. Unfortunately, this feature has seen some security issues in the past, and it’s often recommended to disable the default implementation (like we did in config earlier).
But, there exists a little bit better implementation called securemodelines
,
that supports most of the features, but only those deemed secure.
Plugin: GitGutter
As almost all projects nowadays use git
for their version control needs, it’s
often desirable to have some support for VCS built in your text editor. For
vim
one great tool is plugin called GitGutter
, which shows status of each
line in left side of the window.
Also, some fixes to default config…
" Always show the sign column, removes some annoying on/off toggling
set signcolumn=yes
" Remap hunk modifier keys
nmap ghn <Plug>(GitGutterNextHunk)
nmap ghp <Plug>(GitGutterPrevHunk)
nmap ghs <Plug>(GitGutterStageHunk)
nmap ghu <Plug>(GitGutterUndoHunk)
Plugin: YouCompleteMe
Autocompletion. Let vim suggest you what to write next.
mkdir -p ~/.vim/{plugin,autoload}
ln -s /usr/share/vim-youcompleteme/plugin/youcompleteme.vim ~/.vim/plugin/youcompleteme.vim
ln -s /usr/share/vim-youcompleteme/autoload/youcompleteme.vim ~/.vim/autoload/youcompleteme.vim
Syntax checking
As no-one writes perfect code 100% of the time, it’s nice to have some helpers
for checking your syntax. One nice tool is vim-syntastic
, which does syntax
checking.
" Syntax checks / linting using Syntastic
" Use flake8 for checking Python syntax
let g:syntastic_python_checkers = ["flake8"]
" Use PHP + PHPCS + PHPMD for checking PHP file syntax
let g:syntastic_php_checkers = ['php', 'phpcs', 'phpmd']
" Update status for syntastic
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
Extras
Add some filetype-specific extras (syntax fixes)
" Delete trailing white space on save, useful for eg. Python
func! DeleteTrailingWS()
exe "normal mz"
%s/\s\+$//ge
exe "normal `z"
endfunc
autocmd BufWrite *.py :call DeleteTrailingWS()
" Leader + tws = remove all trailing whitespace
map <leader>tws :%s/\s\+$//e<cr>
Read more
Full example: https://ypcs.fi/misc/code/vim/vimrc.txt