Продвинутая настройка VIM

в 8:44, , рубрики: IDE, linux, python, vim, метки: , ,

Одно из правил эффективного использования редактора гласит следующее — определите, на что у Вас тратится больше всего времени при наборе текста и улучшите это.
Как показывает практика, часто пользователи этого редактора ограничиваются установкой опций, коих конечно не мало. Затем ставят какой-нибудь плагин-мега-пак по советам знатоков, и вроде бы все устраивает, кроме… первого, второго, третьего…
Но ведь если пойти дальше, можно обнаружить бесконечный потенциал для увеличения производительности в использовании своего редактора.

Продвинутая настройка VIM

В этой статье я попытаюсь описать немного продвинутый способ настройки Vim.
Мы рассмотрим с Вами внутренний скриптинг и поймем, что ничего в нем нет страшного, обычный скриптовый язык.
Данный материал рассчитан на довольно подготовленных пользователях редактора Vim. Для тех, кто разобрался, что такое режимы редактора, буферы, окна. Статья написана в стиле «Одна глава — один конкретный рецепт — одно описание синтаксической структуры языка».

История изменений или оператор if else

Приведем пример использования оператора if в Вашем vimrc для установки опций

if version >= 700
    set history=64
    set undolevels=128
    set undodir=~/.vim/undodir/
    set undofile
    set undolevels=1000
    set undoreload=10000
endif

Данный кусок кода включает весьма полезные возможности, доступные начиная с версии 7.00: после того, как вы закрываете редактор(а если точнее, то текущий буффер), в предыдущих версиях история UNDO-REDO терялась. Начиная же с 7.00 появилась возможность записи этой истории в служебные файлы по каждому ранее открытому буфферу.
То есть теперь вы можете сменить буффер, закрыть окно, вообще выключить редактор, но открыв заново какой-либо файл, история Ваших изменений восстановится.

Быстрое переключение буферов или создание своей функции

Переключение между загруженными буферами должно быть быстрым. Не совсем удобно постоянно набирать :bn, :bp, :b#. Поэтому создадим свою функцию переключения и повесим на горячие клавиши этот функционал.

function! ChangeBuf(cmd)
    if (&modified && &modifiable)
        execute ":w"
    endif
    execute a:cmd
endfunction
nnoremap <silent> <C-o> :call ChangeBuf(":b#")<CR>
nnoremap <silent> <C-n> :call ChangeBuf(":bn")<CR>
nnoremap <silent> <C-p> :call ChangeBuf(":bp")<CR>

Как вы знаете, если файл модифицирован, команды :bn, :bp, b# не сработают и выведут предупреждение о том, что надо его сохранить. Для этого мы и пишем эту функцию, в которой осуществляется проверка, модифицирован ли файл и может ли он быть модифицирован вообще.
Здесь мы создаем функцию, аргумент которой примет как раз те команды по переключению буферов, описанный выше.
nnoremap создает привязку определенной комбинации клавиш для какого либо действия. Аргумент <silent> — подавить echo вывод.

Здесь надо дать некоторое пояснение по переменным в .vimrc, а именно практически все они начинаются с какого либо префикса, отделенного от имени двоеточием. Префикс означает область видимости. Вот основные префиксы:
a:var — аргумент функции
b:var — переменная для текущего буфера
g:var — глобальная переменная
l:var — переменная, объявленная в теле функции
v:var — глобальная определенная в самом редакторе Vim

Список буферов или цикл for

Мне не очень нравится вывод буферов по команде :ls, хотя бы из-за того, что вывод многострочный. По-этому разберем пример с циклом for для вывода списка открытых буферов в одной строке. Преимуществом такого решения является то, что я могу вызвать эту функцию где угодно, в том числе в методе, описанном в предыдущем разделе. Получится, что при смене текущего буфера сразу будет отображаться список других открытых буферов.

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

Здесь мы просто формируем строку со списком открытых буферов. Текущий буфер выделяем в квадратных скобках.
Как мы видим, цикл for весьма схож с циклом из того же Python'а

Здесь надо указать, что ряд функций редактора Vim принимают в качестве аргумента так называемое выражение. Для функции bufnr() например выражением может быть, например символ "%" — даст номер текущего буфера, "$" — даст номер последнего буфера. По каждой функции лучше все-таки смотреть :help func()

Автоматически исполняемый скрипт или чтение данных из текущего буфера

Я довольно часто начинаю писать новые скрипты. И мне удобно, что файл может быть сразу исполняемым.

function ModeChange()
    if getline(1) =~ "^#!"
        if getline(1) =~ "bin/"
            silent !chmod a+x <afile>
        endif
    endif
endfunction
au BufWritePost * call ModeChange()

Здесь мы берем и читаем первую строку из файла, и если она начинается с '#!' и в ней есть 'bin/', то делаем файл исполняемым. После вешаем автокоманду на событие BufWritePost.

Автоматическая заготовка скрипта или вставка в текущий буффер

Этот пример связан с предыдущим. Если мы начинаем писать новый скрипт на python'е, было бы удобно, если сразу в нем была заготовка, например, функция main, некоторые import'ы, строка определения интерпретатора. Продемонстрируем.

function! WritePyinit()
    let @q = "
    #!/usr/bin/env pythonn#-*- encoding: utf-8 -*-nnimport sys, warningsnnwarnings.simplefilter('always')nndef main(argv=sys.argv):n    passnnif __name__ == "__main__":n           
sys.exit(main())n"
    execute "0put q"
endfunction
autocmd BufNewFile *.py call WritePyinit()

Все просто. Если у Вас новый файл *.py, в него будет добавлен стандартный код.

Новый файл test.py

#!/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())

Автоматическая документация или пишем vimrc с синтаксисом Python'а

Эта статья была бы не полной, если бы я не показал, как можно делать вставки в .vimrc на другом языке программирования. Покажу это на примере Python.
Код надо документировать. На Python документация часто пишется в виде DocStrings. Покажем пример, как можно по комбинации клавши автоматически переноситься к тому месту, где должна быть документация.

Автодокументация

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

Опять же, ничего хитрого, обычные HERED-Docs.
Здесь мы используем модуль для Python vim. Далее выискиваем начало текущего блока, вставляем туда кавычки для документации и переводим курсор для в начало будущей документации.

Надо учесть то, что для работы этого кода, вам необходима поддержка python в Вашем vim. Проверить это можно следующим образом:

vim --version | grep '+python'

Если есть поддержка, то все хорошо. Если нет, надо либо собрать Vim самому, либо поставить другой пакет. В Debian/Ubuntu/Mint я рекомендую ставить пакет vim-nox

apt-get install nox

Заключение

Статья получилась довольно объемной. Надеюсь, я показал, что маленькие особенности в Ваш редактор можно добавлять довольно просто.
Теперь, разобравшись с основными принципами продвинутой настройки редактора, Вы сможете написать более полезные дополнения, например, комментирование блока выделенного текста, открытие документации каких-либо функций.

Список полезных материалов

Официальный сайт Vim
VIMDOC, с гиперссылками
Документация по модулю vim для python

Автор: vvpoloskin

Источник

Поделиться

* - обязательные к заполнению поля