Список команд
Соглашения
Чтобы сократить размеры данного HowTo, я ввел следующее обозначение: строка
{h, j, k, l} - перемещает курсор в окно, которое находится {слева, внизу, вверху, справа}.
эквивалентна следующим 4 строкам:
h - перемещает курсор в окно, которое находится слева.
j - перемещает курсор в окно, которое находится внизу.
k - перемещает курсор в окно, которое находится вверху.
l - перемещает курсор в окно, которое находится справа.
Команды редактирования
c - полностью аналогична d, но после своего выполнения переводит редактор в режим вставки.
X - аналогична x, но "стирает текст влево, а не вправо". Если проводить аналогии, то x - это клавиша Del, а X - клавиша Backspace.
D - аналогична d$.
C - аналогична c$.
s - аналогична xi.
S - аналогична cc.
. - повторяет предыдущую команду.
I - аналогична ^i.
A - аналогична $a.
- перемещает курсор на ближайшее число и увеличивает его на единицу.
- перемещает курсор на ближайшее число и уменьшает его на единицу.
Работа с текстом в режиме вставки
- удаляет слово перед курсором.
- удаляет все символы от начала строки до курсора.
- вставляет символ, который находится над курсором (в предыдущей строке).
- вставляет символ, который находится под курсором (в следующей строке).
cmd - выполняет команду cmd и возвращается обратно в режим вставки.
Изменение регистра
{g~, gu, gU} - меняют регистр букв на {противоположный, нижний, верхний}.
{g~~, guu, gUU} - меняют регистр букв во всей строке на {противоположный, нижний, верхний}.
Перемещение в тексте
w - переместиться вперед на первую букву слова.
e - переместиться вперед на последнюю букву слова.
b - переместиться назад на первую букву слова.
ge - переместиться назад на последнюю букву слова.
gE, B, W и E - тоже самое, что и ge, b, w, и e, но только в этом случае словом будет считаться любая последовательность букв, разделенных пробельными символами.
( - На одно предложение назад (до точки).
) - На одно предложение вперед (до точки).
{ - На абзац назад (до пустой строки).
} - На абзац вперед (до пустой строки).
$ - перемещает курсор в конец строки.
^ - перемещает курсор на первый непробельный символ в строке.
0 - перемещает курсор на первый символ строки.
g{j, k} - перемещает курсор на одну экранную строку {вниз, вверх}. Когда длинная строка не умещается в одной экранной строке, она разбивается на несколько экранных строк. j и k перемещают по реальным строкам, а gj и gk - по экранным.
fn - перемещает курсор вперед на символ n в текущей строке.
Fn - перемещает курсор назад на символ n в текущей строке.
t, T - аналогичны f и F, но перемещают курсор не на сам символ, а на символ, находящийся перед ним.
; - повторяет поиск, производимый последней командой f, F, t или T.
, - повторяет поиск, производимый последней командой f, F, t или T, но в обратном порядке.
% - перемещает курсор на парную круглую, фигурную или квадратную скобку. Пары можно задать командой :set matchpairs.
:5 или 5G - перемещает курсор на 5 строку.
gg - перемещает курсор на первую строку.
G - перемещает курсор на последнюю строку.
50% - перемещает курсор в середину текста.
H, M, L - перемещают курсор в начало, середину и конец видимой части текста.
{, } - прокручивает текст на половину высоты окна {вниз, вверх}.
{, } - прокручивает текст на одну строку {вниз, вверх}, но при этом не перемещает курсор.
{, } - прокручивает текст {вниз, вверх} на количество строк, равное высоте окна минус 2 строки.
{zs, ze, zt, zz, zb} - прокручивает текст так, чтобы курсор оказался {на левом крае, на правом крае, вверху, в центре, внизу} экрана.
Стоит заметить, что все эти команды можно использовать не только для перемещения курсора или поиска символа, но и комбинировать их с командами копирования и удаления. Например, если у вас есть строка
void foo(int val_1, int val_2);
то поставив курсор за первую круглую скобку и нажав dt), вы очистите все содержимое внутри скобок, т. е. получите строку
void foo();
Режим выделения
v - войти в режим выделения символов.
V - войти в режим выделения строк.
- войти в режим выделения блока текста.
gv - выделяет текст, который был выделен прошлой командой выделения.
o, O - перемещают в режиме выделения курсор в другой конец, чтобы можно было изменить размеры области выделения с разных концов. Команда O необходима при блочном выделении.
J - если у вас выделен блок текста и вы нажмете J, то все строки, содержащиеся в этом блоке сольются в одну.
Редактирование текста в блочном выделении
Все описанные ниже команды необходимо выполнять, когда вы находитесь в режиме блочного выделения (вызывается по комбинации клавиш ).
I - переключает в режим вставки символов в блочное выделение. После того, как вы нажмете I, наберете несколько символов и нажмете клавишу , набранные символы вставятся во все выделенные строки. Например, с помощью этой операции строки
#include
#include
#include
можно преобразовать в
#include
#include
#include
c - аналогична I, но только перед переключением в режим вставки удаляет символы, выделенные в данный момен блоком.
C - аналогична I, но только перед переключением в режим вставки удаляет все символы от левого края выделения, до конца строки.
{~, u, U} - меняют регистр букв на {противоположный, нижний, верхний}
r - если сначала выделить блок текста, а потом нажать r*, то весь блок заполнится символами *.
< и > - сдвигают выделенный текст влево или вправо так, как это делают команды << и >> в обычном режиме.
Использование буфера обмена и регистров
"*yy - скопировать строку в буфер обмена текущего выделения, которую потом можно будет вставить в других приложениях по нажатию на колесико мыши.
"+yy - скопировать строку в буфер обмена, которую потом можно будет вставить в других приложениях по нажатию на Ctrl+V.
"ayy - скопировать строку в регистр a.
"ap - вставить текст из регистра a.
Важно отметить одну особенность при работе с регистрами: имена регистров лежат в диапазоне a-z. Если "ayy копирует строку в регистр a, то "Ayy добавляет строку в регистр a. Это очень важная особенность. Ее очень удобно использовать, когда вы копируете строки из разных частей файла и хотите потом вставить их в одном месте. Но вся ее мощь проявляется при записи и воспроизведении макросов Vim (через клавиши q и @) - если у вас уже существует работающий макрос, который вы хотите расширить, то вам не обязательно записывать все действия заново - достаточно выполнить, например, qA, и набранные вами команды добавятся к уже существующим.
Метки
Каждый раз, когда вы осуществляете поиск или выполняете команды G, gg и т. п, курсор перемещается по тексту. Vim каждый раз запоминает положение курсора и позволяет вам вернуться в предыдущую позицию. Также существует возможность создавать собственные метки.
ma - создает метку с именем a.
`a - перемещает курсор на метку a.
'a - перемещает курсор на начало строки, содержащей метку a.
:marks - показывает все существующие в данный момент метки.
и - перемещение к ранее посещенным меткам назад и вперед.
`` и '' - перейти на предыдущую позицию (разница между `` и '' такая же как и между `a и 'a).
Поиск
/ - включает режим поиска. Символы .*[]^%/\?~$ являются специальными, поэтому при поиске слова, содержащего такие символы, их необходимо предварять символом \. Строка поиска - это обычное регулярное выражение, так что вы можете использовать символы *, ^, $ и т. д. также, как и при записи обычного регулярного выражения. Подробнее о регулярных выражениях Vim можно прочитать в документации.
? - то же, что и /, но только поиск будет производиться в обратном направлении.
n - повторить поиск.
N - повторить поиск в обратном направлении.
* - при нажатии на * будет произведен поиск слова, на котором находится в данный момент курсор.
# - тоже самое, что и *, но в обратном направлении.
g*, g# - тоже самое, что * и #, но со следующей разницей: при поиске 'the' команда * найдет в тексте только слово the, тогда как g* найдет the, there и т. п.
Игнорирование регистра символов при поиске можно задать опцией :set (no)ignorecase.
Также действуют следующие правила:
/слово\c - ищет "слово", игнорируя регистр независимо от настроек.
/слово\C - ищет "слово", учитывая регистр независимо от настроек.
\< и \> означают начало и конец слова. Т. е. при поиске /\ будет найдено только слово the, тогда как при поиске /the будет найдено the, there и т. д.
/word/b+1 - ищет слово word и устанавливает курсор на второй символ (o).
/word/e-1 - ищет слово word и устанавливает курсор второй символ с конца (r).
?word?e - аналогично /word/e, но ищет назад, а не вперед.
Ввод двух поисковых команд
/word
//e
аналогичен одной команде
/word/e
Если в режиме поиска нажимать на клавиши и , то можно перемещаться по истории поиска. Стоит отметить, что если вы ранее искали слова "слово", "словарь" и "слог", то если вы наберете в режиме поиска "слов" и нажмете на клавишу , то Vim предложит вам из истории поиска только "слово" и "словарь".
Командный режим, вызываемый по клавише : также имеет свою историю.
Автозамена
:[address]s/[search]/[repl]/[gcie] - Поиск [search] и замена на [repl] (в режиме VISUAL - без адреса и в выделенной области):
[gcie]:
[без опций] - первого вхождения (в строке).
g - все вхождения (в строке).
c - с запросом подтверждения.
i - игнорируя регистр.
e - подавляет сообщение об ошибке, которое возникает, если найденный шаблон не встречается ни одного раза. [address]:
% - весь текст.
1 - первая строка.
. - текущая строка.
$ - последняя строка.
1,3 - между строками 1-3.
.,$ - от текущей до последней.
Примеры:
:s/text/new_text/ - Заменяет первый встреченный образец text в текущей строке на new_text.
:s/text/new_text/g - Заменяет все образцы text в текущей строке на new_text.
:1,$s/the/THE/g - Начиная с первой строки до последней (строки $), заместить все встреченные the на THE.
:'a,.s/.*/ha ha/ - От строки, помеченной меткой a, до текущей строки, заменить любой текст на строку "ha ha".
:%s/\s\+$// - удаляет пробельные символы в конце строк во всем файле.
:%s/\([^,]*\), \(.*\)/\2 \1/ - преобразовывает
Doe, John
Smith, Peter
в
John Doe
Peter Smith
Ограничение диапазона строк, в которых необходимо произвести автозамену:
:g/search/s/text/new_text/ - заменяет строку text на new_text в строках, содержащих подстроку search. Команда состоит из двух команд: :g/search/ и :s/text/new_text/. Первая выбирает только строки, содержащие подстроку search, а вторая производит в них обычную автозамену.
Автодополнение
и - поиск слова для автодополнения назад и вперед.
Опция ignorecase влияет на работу автодополнения. Если же установлены опции ignorecase и infercase, то если вы наберете "For" и Vim найдет соответствие "fortunately", то результатом будет "Fortunately".
Автодополнение из определенной области поиска:
- имена файлов.
- целые строки.
- макроопределения.
- текущий и включенные (included) файлы.
- слова из словаря.
- слова из тезауруса.
- теги.
- командная строка Vim.
- имена функций и переменных в исходном коде программ с использованием ctags.
- слова из spell словаря.
Перемещение по предлагаемым в меню словам можно осуществлять теми же и .
- Принять выделенное в данный момент в меню слово.
- Возвращается к тому состоянию, которое было до нажатия горячих клавиш автодополнения.
Выравнивание текста
:{center, right} [width] - выравнивает текст по {центру, правому краю}. width - максимальная ширина строки.
Форматирование строк до фиксированной ширины
:set textwidth=72 - задает автоматическое форматирование строк таким, чтобы их длина не превышала 72 символа. Во время набора текста Vim будет сам вставлять необходимые переносы строк. Правда, если вы впоследствии удалите какие-либо символы из уже набранного текста или просто склеите несколько строк, то Vim не станет их переформатировать автоматически.
gqap - заставляет Vim переформатировать текущий параграф.
gggqG - заставляет Vim переформатировать весь текст.
Также, если необходимо переформатировать только часть текста, то достаточно выделить нужные строки и нажать gq.
Преобразование параграфов, разбитых на строки фиксированной ширины, в строки
:g/./,/^$/join
или
:g/\S/,/^\s*$/join
если пустые строки между параграфами содержат пробельные символы.
Редактирование таблиц
При редактировании таблиц или составлении каких-либо блоксхем удобно иметь возможность свободно перемещаться по всему экрану, не обращая внимания на отсутствующие символы в строке. :set virtualedit=all позволяет сделать это. После выполнения данной команды вы можете перемещать курсор, далее по строке, даже если она не содержит ни одного символа. Как только вы вставите в нее хотя бы один символ, все пространство от начало строки до вставленного символа автоматически заполнится пробелами.
Работа с буферами
:ls - отображает список буферов.
:b file_name - переключается на буфер файла file_name. Полное имя файла писать не обязательно - главное ввести такую последовательность символов, которая присутствует только в имени искомого буфера и не присутствует в именах других буферов.
:b{f,n,p,l} - открывает {первый, следующий, предыдущий, последний} буфер.
Работа с окнами
n или :new [file] - создает новое пустое окно и помещает его над текущим окном. Если указано имя файла, то создается окно, в которое загружается указанный файл.
:vnew [file] - аналогична :new, но помещает окно слева относительно текущего.
s или :sp[lit] [file] - создает копию текущего окна и помещает ее над текущим окном. Если указано имя файла, то создается окно, в которое загружается указанный файл.
v или :vs[plit] - аналогична :split, но помещает окно слева относительно текущего.
c или :clo[se] - закрывает окно.
o или :only - закрывает все окна кроме текущего.
W - перескакивает с одного окна на другое.
- или :res[ize] -N - уменьшает высоту окна на одну строку.
+ или :res[ize] +N - увеличивает высоту окна на одну строку.
< или :res[ize] -N - уменьшает ширину окна на одну колонку.
> или :res[ize] +N - увеличивает ширину окна на одну колонку.
:res[ize] [N] - Задает высоту окна.
:vertical res[ize] [N] - Задает ширину окна.
[height]_ - если указано значение height, то делает размер окна равным height, в противном случае увеличивает высоту окна до максимального размера.
[width]| - если указано значение width, то делает ширину окна равной width, в противном случае увеличивает ширину окна до максимального размера.
{h, j, k, l, t, b} - перемещает курсор в окно, которое находится {слева, внизу, вверху, справа, в самом верху, в самом низу}
{H, J, K, L} - перемещает окно так, чтобы оно было {самым левым, самым нижним, самым верхним, самым правым}
= - Делает все окна одинакового размера.
:wa, :qa, :wqa - аналогичны :w, :q и :wq, но производят действия со всеми окнами.
Табы (вкладки)
:tabe[dit] [file] - создает новую вкладку.
gt - переключается между вкладками.
Ngt - Переходит на вкладку с номером N.
:tab split - создает новую вкладку, в которой будет открыт буфер, редактируемый в данный момент.
:tabn[ext][N] или :tabn[ext][N] - Переходит на вкладку с номером N. Если аргумент N опущен, то переходит на следующую вкладку.
:tabm[ove][N] или :tabm[ove][N] - Перемещает текущую вкладку так, чтобы она стояла после вкладки N.
:tabc[lose] [tab_num] - Закрывает вкладку.
:tabo[nly] - Закрывает все вкладки кроме текущей.
:tabr[ewind] или :tabfir[st] - Открывает первую вкладку.
:tabl[ast] - Открывает последнюю вкладку.
:tabp[revious] - Переходит на предыдущую вкладку.
:tabs - Отображает список вкладок с открытыми в них окнами.
Макросы
qa - начать запись в регистр a.
q - окончить запись.
@a - воспроизвести запись из регистра a.
Редактирование командной строки и строки поиска
или - смещает курсор на одно слово влево.
или - смещает курсор на одно слово вправо.
или - в начало строки.
или - в конец строки.
- удаляет слово, стоящее перед курсором.
- удаляет все символы перед курсором.
Сохранение информации о текущей сессии между запусками Vim
Vim запоминает файл и место в файле, в котором находился курсор в момент его закрытия. Если запустить Vim снова и нажать '0, то он откроет этот файл и установит курсор в то же место. При закрытии '0 запишется в '1, '1 в '2 и т. д. до '9. В '0 запишется новое значение.
Сохранение viminfo файла позволяет впоследствии восстановить текущее содержимое регистров, метки, историю поиска и историю команд.
:wviminfo! ~/.vim/my_viminfo - записывает текущую информацию в файл ~/.vim/my_viminfo.
:rviminfo! ~/.vim/my_viminfo - восстанавливает записанную информацию из файла ~/.vim/my_viminfo.
Сохранение текущей сессии позволяет впоследствии восстановить открытые в данный момент окна, их размеры, табы, текущие привязки горячих клавиш, значения переменных и т. п.
:mksession! ~/.vim/my_session - сохраняет информацию о текущей сессии в файл ~/.vim/my_session.
Восстановить сохраненную ранее сессию можно командой
:source ~/.vim/my_session
или запустив Vim с переданной ему опцией -S:
vim -S ~/.vim/my_session
Просмотр бинарных файлов
Запустите Vim командой
vim -b -c '%!xxd' binary_file
Если вам необходимо изменить файл - то поменяйте hex значения (не printable часть) и выполните команду :%!xxd -r - она преобразует обратно hex представление в бинарный файл, который затем можно сохранить.
Внесение изменений во множество файлов
Допустим, что у вас есть много *.c файлов, в которых вы хотите поменять переменную
"x_cnt" на "x_counter".
Для этого вам необходимо произвести следующие действия:
:args *.c
:argdo %s/\/x_counter/gce | update
| - это разделитель команд. Команда update сохраняет файл, если он был изменен.
Также существуют команды :windo и :bufdo, которые действуют соответственно, для всех окон и всех буферов.
Подсветка синтаксиса
Иногда из-за подсветки синтаксиса Vim очень сильно тормозит. :syntax clear позволяет временно отключить подсветку.
После выполнения :syntax manual, все новые файлы, которые вы будете открывать, будут отображаться без подсветки. Чтобы включить подсветку для конкретного файла, нужно будет выполнить команду :set syntax=ON.
Складки
zf - создает новую складку (актуально при foldmethod=manual).
zd - удаляет складку, на которой в данный момент находится курсор.
zD - рекурсивно удаляет все складки под курсором.
zE - удаляет все складки в окне.
zo - открыть текущую складку.
zO - открыть текущую складку и все складки внутри нее.
zc - скрыть текущую складку.
zС - скрыть текущую складку и все складки внутри нее.
za - скрыть/открыть текущую складку.
zA - скрыть/открыть текущую складку и все складки внутри нее.
{zr, zm} - {увеличивает, уменьшает} на 1 уровень сокрытия складок.
{zR, zM} - {открыть, скрыть} все складки.
Метод, по которому будут создаваться складки можно задать через опцию foldmethod:
:set foldmethod=indent
:set foldmethod=manual
:set foldmethod=syntax
Команды zr и zm на самом деле просто увеличивают и уменьшают опцию foldlevel, поэтому вы можете также задать ее самостоятельно:
:set foldlevel=3
zM задает foldlevel=0, а zR - максимальное значение, для текущего файла.
Сборка C/C++ программ средствами make
:cc [line] - показать ошибку. Если указан параметр line, то отображается строка line.
:cn[ext] - отображает следующую ошибку.
:cN[ext] или :cp[revious] - отображает предыдущую ошибку.
:cr[ewind] или :cfir[st] - отображает первую строку вывода make.
:cla[st] - отображает последнюю строку вывода make.
:cl[ist] [from][,[to]] - отображает список ошибок.
:cl[ist]! [from][,[to]] - отображает список всех ошибок, а не только тех, которые подходят под шаблон.
:cw[indow] [height] или :cope[n] [height] - открывает окно с выводом make'a.
:ccl[ose] - закрывает окно, открытое командой :copen.
:make - запускает процесс компиляции. Если запущена не как :make!, то при возникновении ошибок компиляции переходит на эти ошибки в тексте.
:set makeprg=make - задает команду, которую будет запускать :make.
Опция switchbuf задает поведение команд :cn, :make и т. п. относительно того, где они будут открывать требуемый файл (к примеру, значение split заставляет сначала открывать новое окно, и уже в него загружать файл с ошибкой, а не использовать текущее).
Редактирование C/C++ программ
= - вставляет необходимые отступы в выделенных строках C программы.
[i - пытается найти в заголовочных файлах определение идентификатора, на котором в данный момент находится курсор и выводит это определение в статусную строку.
[ - аналогична [i, но только не отображает строку с определением, а открывает файл с исходным кодом на той строке, из которой команда [i взяла бы определение.
[I - отображает список строк из текущего и подключенных к нему заголовочных файлов, в которых находится идентификатор, на котором в данный момент находится курсор.
- перемещает на определение функции C, имя которой находится под курсором (используя ctags).
] - то же самое, что и , но открывает в новом окне.
- перемещает обратно на файл, который был открыт в буфере до выполнения команды .
gd - перемещает к определению переменной внутри текущей функции.
gD - перемещает к определению глобальной переменной, если она определена в этом файле.
% - перемещает к парной (), {}, [], /* */, #if, #else, #endif.
[ - перемещает на первый найденный в текущем и в подключенных файлах #define для идентификатора, на котором в данный момент находится курсор.
[ - перемещает на первое найденное в текущем и в подключенных файлах определение идентификатора, на котором в данный момент находится курсор.
[D - отображает список #define'ов, найденных в текущем и подключенных файлах для идентификатора, на котором в данный момент находится курсор.
[I - отображает список определений, найденных в текущем и подключенных файлах для идентификатора, на котором в данный момент находится курсор.
{], ], ]D, ]I} - аналогична {[, [, [D, [I}, но поиск будет производиться от текущего положения курсора.
[( - производит поиск вверх по тексту и устанавливает курсор на круглой скобке '(', у которой нет парной закрывающей скобки (если такая существует).
Список файлов, в которых будут искаться ctag'и задаются опцией :set tags=./tags,./../tags,./*/tags.
При нажатии на CTRL-] Vim находит метку в ctag'ах и открывает эту метку в буфере. Если одному имени тэга соответствует несколько меток, то переключаться между ними можно командами :tfirst, :[count]tprevious, :[count]tnext и :tlast. :tselect tagname выведет список меток с тегом tagname.
Перемещение по блокам кода
function(int a)
+-> {
| if (a)
| +-> {
[[ | | for (;;) --+
| | +-> { |
| [{ | | foo(32); | --+
| | [{ | if(bar(a)) --+ | ]} |
+-- | +-- break; | ]} | |
| } <-+ | | ][
+-- foobar(a) | |
} <-+ |
} <-+
int func1(void)
{
return 1;
+----------> }
|
[] | int func2(void)
| +-> {
| [[ | if (flag)
start +-- +-- return flag;
| ][ | return 2;
| +-> }
]] |
| int func3(void)
+----------> {
return 3;
}
[(
<--------------------------------
<--------
if (a == b && (c == d || (e > f)) && x > y)
-------------->
-------------------------------->
])
Также не стоит забывать про команду %, которая перемещает на парные (), [] и {}.
Остальные команды
:options - выдает список всех доступных опций, причем опции можно менять прямо в этом списке - изменения сразу же будут вступать в силу. Опции с булевыми значениями меняются клавишей Enter. Чтобы поменять опции, содержащие строковые или числовые значения, необходимо просто отредактировать это значение и нажать клавишу Enter.
:r[ead] filename - вставляет содержимое другого файла в текущий.
:w[rite] [>>]filename - записывает содержимое текущего файла в файл filename. Если указан оператор >>, то информация добавляется в файл, не стирая его содержимого. Команда write также поддерживает диапазоны, например, :.write filename записывает в файл только текущую строку. Если выполнить команду :write в режиме выделения, то в файл запишется выделенный фрагмент текста.
:!cmd - запускает внешнюю команду cmd. Например, :!date выведет текущую дату. Если выделить какой-нибудь текст и в режиме выделения набрать :!sort, то выделенный текст будет отсортирован. :read !ls -1 вставляет список файлов текущей директории в место под курсором. :write !wc -l подсчитывает количество строк в редактируемом тексте.
:cd - меняет текущую директорию Vim'a.
:pwd - выводит текущую директорию Vim'a.
:lcd - меняет текущую директорию окна. По умолчанию все окна имеют одинаковую текущую директорию, которая меняется командой :cd. После выполнения :lcd выполнение :cd в других окнах не влияет на текущую директорию этого окна, пока в нем не будет выполнена :cd.
gf - открывает файл, на имя которого в данный момент указывает курсор. Если загружен плагин netrw, то можно открывать файлы по протоколам ftp, http, scp и rcp.
f - аналогично gf, но открывает файл в новом окне.
:map - показывает список привязок горячих клавиш.
:set lazyredraw - отключает перерисовку экрана на время выполнения макроса (существенно ускоряет работу).
Аналоги стандартных клавиш
При десятипальцевом слепом методе набора текста гораздо удобнее нажимать нежели , т. к. для нажатия не требуется убирать руки с клавиатуры, что влечет за собой увеличение скорости работы.
-
-
-
-
http://habrahabr.ru/blog/vim/47805.html