Advanced VIM configuration
- Tutorial
As practice shows, often users of this editor are limited to installing options, of which there are certainly not a few. Then they put some kind of plug-in mega-pack on the advice of experts, and everything seems to be fine, except ... the first, second, third ...
But if you go further, you can discover infinite potential for increasing productivity in using your editor.

In this article, I will try to describe a slightly advanced way to configure Vim.
We will consider internal scripting with you and understand that there is nothing terrible in it, an ordinary scripting language.
This material is designed for fairly trained users of the Vim editor. For those who understand what editor modes, buffers, windows are. The article is written in the style of "One chapter - one specific recipe - one description of the syntactic structure of the language."
Change history or if else statement
Here is an example of using the if statement in your vimrc to set options
if version >= 700
set history=64
set undolevels=128
set undodir=~/.vim/undodir/
set undofile
set undolevels=1000
set undoreload=10000
endif
This piece of code includes some very useful features available since version 7.00: after you close the editor (or rather, the current buffer), in previous versions the history of UNDO-REDO was lost. Starting from 7.00 it became possible to record this story in the service files for each previously opened buffer.
That is, now you can change the buffer, close the window, turn off the editor altogether, but by opening a file again, the history of your changes will be restored.
Quickly switch buffers or create your own function
Switching between loaded buffers should be quick. It’s not very convenient to constantly type: bn,: bp,: b #. Therefore, we will create our own switching function and put this functionality on the hot keys.
function! ChangeBuf(cmd)
if (&modified && &modifiable)
execute ":w"
endif
execute a:cmd
endfunction
nnoremap :call ChangeBuf(":b#")
nnoremap :call ChangeBuf(":bn")
nnoremap :call ChangeBuf(":bp") As you know, if the file is modified, the commands: bn,: bp, b # will not work and will warn you that it must be saved. To do this, we write this function, which checks whether the file is modified and whether it can be modified at all.
Here we create a function, the argument of which will take just those commands for switching buffers described above.
nnoremap creates a binding of a certain key combination for any action. Argument \
Here we need to give some explanation on the variables in .vimrc, namely, almost all of them start with some kind of prefix, separated from the name by a colon. The prefix means the scope. Here are the main prefixes:
a: var - function argument
b: var - variable for the current buffer
g: var - global variable
l: var - variable declared in the body of function
v: var - global defined in the Vim editor itself
Buffer list or for loop
I don’t really like the output of the buffers on the command: ls, if only because the output is multi-line. Therefore, we will analyze an example with a for loop to display a list of open buffers on one line. The advantage of this solution is that I can call this function anywhere, including in the method described in the previous section. It turns out that when you change the current buffer, a list of other open buffers will immediately be displayed.
function! BufList()
let status = ""
for i in range(1, last_buffer_nr()+1)
if bufnr("%") == i
let status = status . ' ' . '[' . bufname(i) . ']' "объединяем строки
continue
endif
if buflisted(i)
let status = status . ' ' . bufname(i)
endif
endfor
return status
endfunction
Here we simply form a line with a list of open buffers. Select the current buffer in square brackets.
As we can see, the for loop is very similar to the loop from the same Python.
Here you need to indicate that a number of functions of the Vim editor take the so-called expression as an argument. For the bufnr () function, for example, the expression can be, for example, the symbol "%" - will give the number of the current buffer, "$" - will give the number of the last buffer. For each function, it's better to watch: help func ()
Automatically executed script or reading data from the current buffer
I often start writing new scripts. And it’s convenient for me that the file can be immediately executable.
function ModeChange()
if getline(1) =~ "^#!"
if getline(1) =~ "bin/"
silent !chmod a+x
endif
endif
endfunction
au BufWritePost * call ModeChange()
Here we take and read the first line from the file, and if it starts with '#!' and it has 'bin /', then make the file executable. After we hang the auto command on the BufWritePost event.
Automatically prepare a script or paste into the current buffer
This example is related to the previous one. If we start writing a new script in python, it would be convenient if there was a blank in it right away, for example, the main function, some imports, and the interpreter definition line. Demonstrate.
function! WritePyinit()
let @q = "
\#\!/usr/bin/env python\n\#-*- encoding: utf-8 -*-\n\nimport sys, warnings\n\nwarnings.simplefilter('always')\n\ndef main(argv=sys.argv):\n pass\n\nif __name__ == \"__main__\":\n
sys.exit(main())\n"
execute "0put q"
endfunction
autocmd BufNewFile *.py call WritePyinit()
Everything is simple. If you have a new * .py file, the standard code will be added to it.
#!/usr/bin/env python
#-*- encoding: utf-8 -*-
import sys, warnings
warnings.simplefilter('always')
def main(argv=sys.argv):
pass
if __name__ == "__main__":
sys.exit(main())
Automated documentation or writing vimrc with Python syntax
This article would not be complete if I had not shown how to insert in .vimrc in another programming language. I will show it on the example of Python.
The code must be documented. In Python, documentation is often written as DocStrings. Let us show an example of how, by a combination of keys, it is automatically transferred to the place where the documentation should be.
function! WriteDocstrings()
python <
Опять же, ничего хитрого, обычные HERED-Docs.
Здесь мы используем модуль для Python vim. Далее выискиваем начало текущего блока, вставляем туда кавычки для документации и переводим курсор для в начало будущей документации.
Надо учесть то, что для работы этого кода, вам необходима поддержка python в Вашем vim. Проверить это можно следующим образом:
vim --version | grep '+python'
Если есть поддержка, то все хорошо. Если нет, надо либо собрать Vim самому, либо поставить другой пакет. В Debian/Ubuntu/Mint я рекомендую ставить пакет vim-nox
apt-get install nox
Заключение
Статья получилась довольно объемной. Надеюсь, я показал, что маленькие особенности в Ваш редактор можно добавлять довольно просто.
Теперь, разобравшись с основными принципами продвинутой настройки редактора, Вы сможете написать более полезные дополнения, например, комментирование блока выделенного текста, открытие документации каких-либо функций.
Список полезных материалов
Официальный сайт Vim
VIMDOC, с гиперссылками
Документация по модулю vim для python
UPD1: чищеный от приватки vimrc"
" Comments/uncomments strings and selected text
" When buffer changing try to save it
" Convinient view of statusline
" AutoResave sessions on exit
" Auto settings for DJANGO omni completion
"
"Mapped Keys
" Mode Combination Description
" N Next buffer with saving if possible
" N Prev buffer with saving if possible
" N Last viewed buffer
" N Clear highlighting after searching
" I Set normal mode
" N Comment Lines
" N Uncomment Lines
" I Show popup menu OmniCompletion
" I If popupmenu is showed list it elements
" NIV Bonding Mode(useful when pasting from X-buffer)
" I Left in insert mode
" I Down in insert mode
" I Up in insert mode
" I Right in insert mode
" N ,p Paste after
" N ,P Paste before
" N Down in long line
" N Up in long line
" V Comment Line
" V Uncomment Line
filetype on
filetype plugin on
set tabstop=4
set shiftwidth=4
set smarttab
set expandtab
set softtabstop=4
set autoindent
let python_highlight_all = 1
set t_Co=256
autocmd FileType html,xhtml,xml,htmldjango,htmljinja,eruby,mako setlocal noexpandtab
autocmd FileType *.py set tw=80
autocmd FileType python nnoremap :call WriteDocstrings()
"nnoremap :call WriteDocstrings()
autocmd BufWritePre *.py normal m`:%s/\s\+$//e ``
autocmd BufRead *.py set smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class
autocmd BufNewFile *.py call WritePyinit()
autocmd VimLeave * !reset
set nu
set ruler
set mousehide
syntax on
set backspace=indent,eol,start whichwrap+=<,>,[,]
set showtabline=0
set foldcolumn=1
set wrap
set linebreak
set nobackup
set noswapfile
set encoding=utf-8
set fileencodings=utf8,cp1251
"Searchig options
set showmatch
set hlsearch
set incsearch
"Layouts
set fencs=utf-8,cp1251,koi8-r,ucs-2,cp866
"memory, history, undotree
if version >= 700
set history=64
set undolevels=128
set undodir=~/.vim/undodir/
set undofile
set undolevels=1000
set undoreload=10000
endif
"Sessions - сохранение текущих буферов, регистров.
set sessionoptions=buffers,tabpages,help,blank,globals,localoptions,sesdir,slash,options
function! SaveSession(...)
if v:this_session != ""
function Tmp(filename)
execute ":mksession! ".v:this_session
endfunction
autocmd VimLeavePre * :call Tmp("xxx")
endif
endfunction
au SessionLoadPost * :call SaveSession()
"Titles, statuses
set laststatus=2
set showtabline=2
set title
set statusline=%1*%m%*%2*%r%*%3*%h%w%*%{expand(\"%:p:~\")}\ %<
set statusline+=%=Col:%3*%03c%*\ Ln:%3*%04l/%04L%*
set statusline+=%(\ File:%3*%{join(filter([&filetype,&fileformat!=split(&fileformats,\",\")[0]?&fileformat:\"\",&fileencoding!=split(&fileencodings,\",\")[0]?&fileencoding:\"\"],\"!empty(v:val)\"),\"/\")}%*%)
set titlestring=%t%(\ %m%)%(\ %r%)%(\ %h%)%(\ %w%)%(\ (%{expand(\"%:p:~:h\")})%)\ -\ VIM
"autocmd VimLeavePre * silent mksession! ~/.vim/lastSession.vim
"autocmd VimEnter * silent source! ~/.vim/lastSession.vim
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
set langmap=йq,цw,уe,кr,еt,нy,гu,шi,щo,зp,х[,ъ],фa,ыs,вd,аf,пg,рh,оj,лk,дl,ж\\;,э',яz,чx,сc,мv,иb,тn,ьm,б\\,,ю.,ё`,ЙQ,ЦW,УE,КR,ЕT,НY,ГU,ШI,ЩO,ЗP,Х{,Ъ},ФA,ЫS,ВD,АF,ПG,РH,ОJ,ЛK,ДL,Ж:,Э\\",ЯZ,ЧX,СC,МV,ИB,ТN,ЬM,Б<,Ю>,Ё~
"Buffers
function! ChangeBuf(cmd)
if (&modified && &modifiable)
execute ":w"
endif
execute a:cmd
endfunction
nnoremap :call ChangeBuf(":b#")
nnoremap :call ChangeBuf(":bn")
nnoremap :call ChangeBuf(":bp")
nnoremap Oj
inoremap
nnoremap :nohlsearch
inoremap I
inoremap A
function! BufList()
let status = ""
for i in range(1, last_buffer_nr()+1)
if bufnr("%") == i
let status = status . ' ' . '[' . bufname(i) . ']'
continue
endif
if buflisted(i)
let status = status . ' ' . bufname(i)
endif
endfor
return status
endfunction
"Copy/Paste
if has("clipboard")
set clipboard=autoselect
endif
"Autoaddition
set formatoptions-=o
"scripting
function ModeChange()
if getline(1) =~ "^#!"
if getline(1) =~ "bin/"
silent !chmod a+x
endif
endif
endfunction
au BufWritePost * call ModeChange()
if expand("%:t") =~ "py$"
set makeprg=python
endif
if expand("%:t") =~ "sh$"
set makeprg=/bin/bash
endif
if !has("gui_running")
imap
else
imap
endif
filetype plugin on
set ofu=syntaxcomplete#Complete
set complete=.,b,t,k,u,k
set completeopt-=preview
set completeopt+=longest
autocmd FileType python set omnifunc=pythoncomplete#Complete
autocmd FileType javascript set omnifunc=javascriptcomplete#CompleteJS
autocmd FileType html set omnifunc=htmlcomplete#CompleteTags
autocmd FileType css set omnifunc=csscomplete#CompleteCSS
if expand("%:t") =~ "^.*\.py$"
let $PYTHONPATH = fnamemodify("%", ":p:h:h")
let $DJANGO_SETTINGS_MODULE = fnamemodify("%", ":p:h:t").".settings"
endif
set completeopt=longest,menuone
"Режим склейки при вставке
"set paste
"set nopaste
"set invpaste
set pastetoggle=
"Folding
set foldenable
set foldmethod=syntax
autocmd FileType tex set foldmethod=indent
"Цветовая схема
"color blackboard
let g:solarized_termcolors=256
colorscheme solarized
set background=dark
"Remaps
inoremap h
inoremap j
inoremap k
inoremap l
nnoremap ,p op
nnoremap ,P Op
nnoremap gj
nnoremap gk
"Автокомменты
nnoremap :call CommentLine()
nnoremap :call UnCommentLine()
vmap :call CommentLine()
vmap :call UnCommentLine()
"скрипты
function! WritePyinit()
let @q = "
\#\!/usr/bin/env python\n\#-*- encoding: utf-8 -*-\n\nimport sys, warnings\n\nwarnings.simplefilter('always')\n\ndef main(argv=sys.argv):\n pass\n\nif __name__ == \"__main__\":\n sys.exit(main())\n"
execute "0put q"
endfunction
function! WriteDocstrings()
if !has('python')
echo "Error: Required vim compiled with +python"
finish
endif
python <A" . endsymbol . "\"
endfunction
function! UnCommentLine()
let file_name = buffer_name("%")
let stsymbol = b:comment[0]
let endsymbol = b:comment[0]
execute ":silent! normal :s/^\s*" . stsymbol . "//\"
execute ":silent! normal :s/\s*" . endsymbol . "\s*$//\"
endfunction
let ropevim_vim_completion=1
function! CmdLine(str)
exe "menu Foo.Bar :" . a:str
emenu Foo.Bar
unmenu Foo
endfunction
" From an idea by Michael Naumann
function! VisualSearch(direction) range
let l:saved_reg = @"
execute "normal! vgvy"
let l:pattern = escape(@", \/.*$^~[])
let l:pattern = substitute(l:pattern, "\n$", "", "")
if a:direction == b
execute "normal ?" . l:pattern . "^M"
elseif a:direction == gv
call CmdLine("vimgrep " . /. l:pattern . / . **/*.)
elseif a:direction == f
execute "normal /" . l:pattern . "^M"
endif
let @/ = l:pattern
let @" = l:saved_reg
endfunction
"Basically you press * or # to search for the current selection
vnoremap * :call VisualSearch('f')
vnoremap # :call VisualSearch('b')
vnoremap gv :call VisualSearch('gv')
"PYDOC
if exists('*s:ShowPyDoc') && g:pydoc_perform_mappings
call s:PerformMappings()
finish
endif
if !exists('g:pydoc_perform_mappings')
let g:pydoc_perform_mappings = 1
endif
if !exists('g:pydoc_highlight')
let g:pydoc_highlight = 1
endif
if !exists('g:pydoc_cmd')
let g:pydoc_cmd = 'pydoc'
endif
if !exists('g:pydoc_open_cmd')
let g:pydoc_open_cmd = 'split'
endif
setlocal switchbuf=useopen
highlight pydoc cterm=reverse gui=reverse
function s:ShowPyDoc(name, type)
if a:name == ''
return
endif
if g:pydoc_open_cmd == 'split'
let l:pydoc_wh = 10
endif
if bufloaded("__doc__")
let l:buf_is_new = 0
if bufname("%") == "__doc__"
" The current buffer is __doc__, thus do not
" recreate nor resize it
let l:pydoc_wh = -1
else
" If the __doc__ buffer is open, jump to it
silent execute "sbuffer" bufnr("__doc__")
let l:pydoc_wh = -1
endif
else
let l:buf_is_new = 1
silent execute g:pydoc_open_cmd '__doc__'
if g:pydoc_perform_mappings
call s:PerformMappings()
endif
endif
setlocal modifiable
setlocal noswapfile
setlocal buftype=nofile
setlocal bufhidden=delete
setlocal syntax=man
silent normal ggdG
" Remove function/method arguments
let s:name2 = substitute(a:name, '(.*', '', 'g' )
" Remove all colons
let s:name2 = substitute(s:name2, ':', '', 'g' )
if a:type == 1
execute "silent read !" g:pydoc_cmd s:name2
else
execute "silent read !" g:pydoc_cmd "-k" s:name2
endif
normal 1G
if exists('l:pydoc_wh') && l:pydoc_wh != -1
execute "silent resize" l:pydoc_wh
end
if g:pydoc_highlight == 1
execute 'syntax match pydoc' "'" . s:name2 . "'"
endif
let l:line = getline(2)
if l:line =~ "^no Python documentation found for.*$"
if l:buf_is_new
execute "bdelete!"
else
normal u
setlocal nomodified
setlocal nomodifiable
endif
redraw
echohl WarningMsg | echo l:line | echohl None
else
setlocal nomodified
setlocal nomodifiable
endif
endfunction
" Mappings
function s:PerformMappings()
nnoremap pw :call ShowPyDoc('', 1)
nnoremap pW :call ShowPyDoc('', 1)
nnoremap pk :call ShowPyDoc('', 0)
nnoremap pK :call ShowPyDoc('', 0)
" remap the K (or 'help') key
nnoremap K :call ShowPyDoc(expand(""), 1)
endfunction
if g:pydoc_perform_mappings
call s:PerformMappings()
endif
" Commands
command -nargs=1 Pydoc :call s:ShowPyDoc('', 1)
command -nargs=* PydocSearch :call s:ShowPyDoc('', 0)