📜 ⬆️ ⬇️

Advanced VIM Setup

One of the rules for effective use of the editor says the following - determine what you spend most time typing, and improve it.
As practice shows, often users of this editor are limited to installing options, which of course is not small. Then they put some plugin-mega-pack on the advice of experts, and everything seems to be fine, except ... first, second, third ...
But if you go further, you can find an infinite potential for increased productivity in the use of its editor.



In this article I will try to describe a slightly advanced way to tweak Vim.
We will consider internal scripting with you and we will understand that there is nothing terrible in it, an ordinary scripting language.
This material is designed for fairly trained users of the editor Vim. For those who figured out what are editor modes, buffers, windows. 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 an 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 very useful features available since version 7.00: after you close the editor (or, more precisely, the current buffer), in previous versions the history of UNDO-REDO was lost. Starting from 7.00, it became possible to record this history in 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 again any file, the history of your changes will be restored.

Fast switching buffers or creating your own function


Switching between loaded buffers should be fast. It is not very convenient to constantly dial: bn,: bp,: b #. Therefore, we will create our own switching function and hang this functionality on the hotkeys.
 function! ChangeBuf(cmd) if (&modified && &modifiable) execute ":w" endif execute a:cmd endfunction nnoremap <silent> <Co> :call ChangeBuf(":b#")<CR> nnoremap <silent> <Cn> :call ChangeBuf(":bn")<CR> nnoremap <silent> <Cp> :call ChangeBuf(":bp")<CR> 

As you know, if the file is modified, the commands: bn,: bp, b # will not work and will display a warning that you need to save it. For this we write this function, in which we check whether the file is modified and whether it can be modified at all.
Here we create a function whose argument will take just those commands for switching buffers, described above.
nnoremap creates a binding of a specific key combination for an action. Argument \ <silent \> - suppress echo output.

Here it is necessary to give some explanation on the variables in .vimrc, namely, almost all of them begin with some prefix, separated from the name by a colon. Prefix means scope. Here are the basic prefixes:
a: var - function argument
b: var - variable for current buffer
g: var - global variable
l: var is a variable declared in the function body
v: var - global defined in the Vim editor itself

Buffer list or for loop


I do not really like the output of buffers on the command: ls, if only because the output is multiline. Therefore, we analyze an example with a for loop to display a list of open buffers in 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 be immediately 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. We 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 it is necessary to point out that a number of functions of the Vim editor accept the so-called expression as an argument. For the function bufnr () for example, the expression may be, for example, the character "%" gives the number of the current buffer, "$" gives the number of the last buffer. For each function, it's better to still watch: help func ()


Automatically executable script or reading data from the current buffer


I often start writing new scripts. And it is convenient for me that the file can be immediately executable.
 function ModeChange() if getline(1) =~ "^#!" if getline(1) =~ "bin/" silent !chmod a+x <afile> endif endif endfunction au BufWritePost * call ModeChange() 

Here we take and read the first line from the file, and if it starts with '#!' and there is a 'bin /' in it, then we make the file executable. After we hang the autocommand on the BufWritePost event.

Automatic preparation of the script or insert 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 immediately a blank in it, for example, the main function, some imports, the interpreter definition line. Let's 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() 

It's simple. If you have a new * .py file, the standard code will be added to it.
New test.py file
 #!/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()) 



Automatic documentation or write vimrc with Python syntax


This article would not be complete if I didn’t show how to insert into .vimrc in another programming language. I'll show it on the example of Python.
The code must be documented. Python documentation is often written as DocStrings. Let us show an example of how it is possible by the combination of the keys to automatically be transferred to the place where the documentation should be.
Autodocumentation
 function! WriteDocstrings() python <<EOF import vim import re linenr = vim.current.window.cursor[0] indentr = vim.current.window.cursor[0] line = vim.current.line n = 0 for i in line: if i != ' ': break n += 1 if len(line) == 0: n = 0 vim.current.buffer.append(' '*n + ' '*4 + '"""', linenr) vim.current.buffer.append(' '*n + ' '*4 + '', linenr) vim.current.buffer.append(' '*n + ' '*4 + '"""', linenr) vim.current.window.cursor = (vim.current.window.cursor[0]+2, n+4) EOF endfunction 

Again, nothing tricky, ordinary HERED-Docs.
Here we use the module for Python vim. Next, we search for the beginning of the current block, insert quotes for documentation there, and move the cursor to the beginning of the future documentation.

You need to take into account that in order for this code to work, you need python support in your vim. You can check this as follows:
 vim --version | grep '+python' 

If there is support, then everything is fine. If not, you must either build Vim yourself, or put another package. In Debian / Ubuntu / Mint, I recommend installing the vim-nox package.
 apt-get install nox 



Conclusion


The article was quite voluminous. I hope I showed that you can add little features to your editor quite simply.
Now, having understood the basic principles of advanced editor settings, you can write more useful additions, for example, commenting on a block of selected text, opening documentation of any functions.

List of useful materials

Vim official website
VIMDOC, with hyperlinks
Vim for python module documentation

UPD1: vimrc peeled off
 " " 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 <Cn> Next buffer with saving if possible " N <Cp> Prev buffer with saving if possible " N <Co> Last viewed buffer " N <Ce> Clear highlighting after searching " I <Cq> Set normal mode " N <Cc> Comment Lines " N <Cu> Uncomment Lines " I <C-Space> Show popup menu OmniCompletion " I <Tab> If popupmenu is showed list it elements " NIV <F5> Bonding Mode(useful when pasting from X-buffer) " I <Ah> Left in insert mode " I <Aj> Down in insert mode " I <Ak> Up in insert mode " I <Al> Right in insert mode " N ,p Paste after " N ,P Paste before " N <Cj> Down in long line " N <Ck> Up in long line " V <Cc> Comment Line " V <Cu> 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 <Ca> :call WriteDocstrings()<CR> "nnoremap <Ca> :call WriteDocstrings()<CR> 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 <silent> <Co> :call ChangeBuf(":b#")<CR> nnoremap <silent> <Cn> :call ChangeBuf(":bn")<CR> nnoremap <silent> <Cp> :call ChangeBuf(":bp")<CR> nnoremap <C-CR> O<ESC>j inoremap <Cq> <ESC> nnoremap <Ce> :nohlsearch<CR> inoremap <Ce> <ESC>I inoremap <Ca> <ESC>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 <afile> 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 <C-@> <CX><CO> else imap <C-Space> <CX><CO> 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=<F5> "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 <Ah> <Co>h inoremap <Aj> <Co>j inoremap <Ak> <Co>k inoremap <Al> <Co>l nnoremap ,p o<ESC>p nnoremap ,P O<ESC>p nnoremap <Cj> gj nnoremap <Ck> gk " nnoremap <Cc> :call CommentLine()<cr> nnoremap <Cu> :call UnCommentLine()<cr> vmap <Cc> :call CommentLine()<cr> vmap <Cu> :call UnCommentLine()<cr> " 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 <<EOF import vim import re linenr = vim.current.window.cursor[0] indentr = vim.current.window.cursor[0] line = vim.current.line n = 0 for i in line: if i != ' ': break n += 1 if len(line) == 0: n = 0 vim.current.buffer.append(' '*n + ' '*4 + '"""', linenr) vim.current.buffer.append(' '*n + ' '*4 + '', linenr) vim.current.buffer.append(' '*n + ' '*4 + '"""', linenr) vim.current.window.cursor = (vim.current.window.cursor[0]+2, n+4) EOF endfunction """""""""""""""" "  """""""""""""""" function __is_django_template() let l:a = getpos(".") if search("{\%.*\%}", '', line("$")) != 0 let b:b = cursor(l:a[1], l:a[2], "off") return 1 endif return 0 endfunction function RetFileType() let file_name = buffer_name("%") if file_name =~ '\.vim' return ["\"", ""] elseif __is_django_template() == 1 return ['{% comment %}' , '{% endcomment %}'] elseif file_name =~ '\.html$' || file_name =~ '\.xhtml$' || file_name =~ '\.xml' return ["<!--", "-->"] endif return ["#", ""] endfunction au BufEnter * let b:comment = RetFileType() function! CommentLine() let stsymbol = b:comment[0] let endsymbol = b:comment[1] execute ":silent! normal 0i" . stsymbol . "\<ESC>A" . endsymbol . "\<ESC>" endfunction function! UnCommentLine() let file_name = buffer_name("%") let stsymbol = b:comment[0] let endsymbol = b:comment[0] execute ":silent! normal :s/^\s*" . stsymbol . "//\<CR>" execute ":silent! normal :s/\s*" . endsymbol . "\s*$//\<CR>" 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 <silent> * :call VisualSearch('f')<CR> vnoremap <silent> # :call VisualSearch('b')<CR> vnoremap <silent> gv :call VisualSearch('gv')<CR> "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 <silent> <buffer> <Leader>pw :call <SID>ShowPyDoc('<CR><CW>', 1)<CR> nnoremap <silent> <buffer> <Leader>pW :call <SID>ShowPyDoc('<CR><CA>', 1)<CR> nnoremap <silent> <buffer> <Leader>pk :call <SID>ShowPyDoc('<CR><CW>', 0)<CR> nnoremap <silent> <buffer> <Leader>pK :call <SID>ShowPyDoc('<CR><CA>', 0)<CR> " remap the K (or 'help') key nnoremap <silent> <buffer> K :call <SID>ShowPyDoc(expand("<cword>"), 1)<CR> endfunction if g:pydoc_perform_mappings call s:PerformMappings() endif " Commands command -nargs=1 Pydoc :call s:ShowPyDoc('<args>', 1) command -nargs=* PydocSearch :call s:ShowPyDoc('<args>', 0) 

Source: https://habr.com/ru/post/165723/


All Articles