Как часто мы ограничиваем понимание привычными шаблонами? Все наверняка знают, что vim — это текстовый редактор, со встроенным скриптовым языком. И сравнивают vim с другими редакторами, иногда даже с IDE.

Мне в голову пришла аналогия, которая возможно несколько ближе к пониманию возможностей vim. Либо же это можно считать еще одной гранью функционала vim. Прошу простить за очередное повторение всеми измученной темы, но меня не оставляют равнодушными споры об этом «редакторе». Возможно среди вас тоже есть такие люди.

Ранее где-то на просторах Хабра писали про киллер-фичу vim'a — режимы. На что было высказано резонное замечание: режимы усложняют выполнение простых операций (среди множества других, не менее резонных комментариев). Я в работе постоянно использую vim и не могу отрицать, что режимы действительно усложняют работу в самых простых случаях. Но давайте рассмотрим возможности vim'a как эзотерического языка редактирования текста.

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

vmap \c :s!^!//!<CR>
vmap \u :s!^//!!<CR>

Мне подобные вещи напоминают примеры программ на Brainfuck (хотя vim команды на мой взгляд немного попроще):

++++++++++[>+++++++>++++++++++>+++<<<-]>++.>+.+++++++
 ..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.

Или например в моем конфиг файле можно найти замечательную строчку:

ve"aydeBvE"by

Какие выводы из этого можно сделать?

Википедия просвещает:
Общее свойство, присущее любому эзотерическому языку — текст программы на нём понятен лишь «посвящённому» либо непонятен вообще.

Т.е. я не считаю, что vim следует изучать кому-либо. Точно так же как никто не будет утверждать, что умение писать на Brainfuck облегчит кому-либо жизнь. Однако, если у вас достаточно свободного времени и вы (как и я) любите необычные вещи, тогда я сделаю краткое введение в эту эзотерическую науку — владение vim. Сделаю небольшую оговорку, речь не идет о vimscript — встроенном языке скриптинга vim. Речь только о представлении команд vim как отдельного языка программирования.

Нет смысла писать про разные режимы работы в vim, по-настоящему вам понадобится только один режим — командный. Можно даже сказать, что режим ввода текста нужен только для того, чтобы не перегружать командный режим возможностями ввода текста. Поэтому я сгруппирую материал по другому принципу — по возможностям команд.

Команды перемещения по тексту


На мой взгляд с хорошего детального изучения этой возможности следует начинать знакомство с vim. Краткий перечень того, что я использую регулярно:

h,j,k,l — перемещение курсора на один символ влево, вниз, вверх, вправо соответственно.
/word — перемещение курсора к позиции слова word в тексте (то, что непосвященные называют поиском).
?word — поиск в обратном направлении (да, я тоже непосвященный).

Здесь и далее по-хорошему следовало оставить формулировку с перемещением вместо поиска (потому как это ключевой момент команды), но я слишком ленив для таких длинных фраз.
n — перемещение к следующей позиции слова из поиска в тексте.
N — то же самое в обратную сторону.
* — поиск слова под курсором.
# — то же самое в обратную сторону.
f[a-z] — перемещение к позиции в строке символа, переданного как параметр.
F[a-z] — то же самое в обратную сторону.
w,b — перемещение на слово вперед, назад соответственно.
m[a-z] — поставить в тексте закладку с именем символа, переданного как параметр.
`[a-z] — перейти к закладке по имени.
() — перемещение к предыдущему, следующему предложению.
{} — перемещение к предыдущему, следующему абзацу.
% — перемещение к соответствующей скобке (){}[] (от открывающей к закрывающей и обратно).

Просто запомнить это сложно и скучно, нужно использовать в повседневных задачах. Пусть ваши руки запомнят эти команды так же, как они научились слепой печати — через постоянные тренировки.

Далее команды редактирования. Их можно было бы выделить в отдельную категорию, но без команд перемещения они бесполезны. И к тому же их совсем немного. В своей практике можно вообще ограничиться тремя:
d — удалить без перехода в режим ввода текста.
c — удалить с переходом в режим ввода текста.
y — скопировать текст, не внося изменений.
v — выделить текст.

Последние две не совсем подходят под команду редактирования, но ведут себя аналогично первым двум.

Некоторые связки команд редактирования и перемещения действуют через вспомогательный режим выделения — v. Т.е. сначала выделяем требуемый кусок кода, затем удаляем.

Несколько примеров:
de — удалить слово
v/a<Enter>d — удалить от текущей позиции до первой позиции символа «a»
dta — удалить до первой позиции в строке символа «a»

Переменные


Переменные в vim называются регистры. Есть несколько специальных регистров:
0 — последний скопированный текст.
+ — текст из буфера обмена.

И именованные a-z, содержимое которых устанавливается явно командой "[a-z] добавленной как параметр к команде редактирования. Т.е. ve"ay — выделить слово и скопировать в регистр а. Добавить текст к содержимому регистра можно, указав его имя с большой буквы ve"Ay.
Содержимое всех регистров можно посмотреть командой :registers

Макросы


Самая полезная, на мой взгляд, функция эзотерического языка. Аналог процедур в обычных языках. Функционал, достаточно редко упоминаемый, но очень часто мной используемый.

Текст макроса сохраняется в именованном регистре и может быть вызван по имени.
q[a-z] — начать запись
q — остановить запись
@[a-z] — выполнить макрос (вызвать процедуру)

Например, если следующий текст ve"Ay поместить в именованный регистр b, а затем набрать @b, слово под курсором будет добавлено к регистру а. Соответственно последовательность команд qbve"Ayq аналогична записи макроса в регистр b с параллельным выполнением команд (т.е. можно наблюдать результат в процессе записи).

Повторный запуск


Все команды редактирования и макросы можно запускать с параметром — количество итераций. Например 5de — удалит 5 слов, 5@b — запустит макрос b 5 раз. Так же есть команда "." — повторение последней выполненной команды. Т.е. 5de. — удалит 10 слов.

Пример


Для первого знакомства, думаю, достаточно. В завершение покажу небольшой пример. Допустим у нас есть список колонок и соответствующих таблиц:

Col1, Table1
Col2, Table2
Col3, Table3


И мы хотим на каждую пару написать select с объединением результата в один набор данных (т.е. union all). Конечно эту задачу можно решить любым другим более адекватным способом. И даже лучше ее решать адекватными способами. Но это слишком просто.

Текст программы будет выглядеть следующим образом:

qq0iselect <Esc>,s from<Esc> union all<Esc>0q2@q

Пару слов о том, что осталось за рамками


1. Плагины vim.
2. VimScript.
3. Ed.
4. Еще куча интересных команд.

VimScript — скриптовый язык, встроенный в vim (уже упоминал выше). Ed — это текстовый редактор, встроенный в vim (возможно не слишком корректно выразился, но суть близка к этому). У него совершенно отдельный синтаксис, но с ним в некоторой степени знакомы все, кто пользовался утилитой sed. В ed есть перемещение/удаление строк, вывод на экран и некоторые другие функции.

На этом все. Happy vimming!

Комментарии (2)


  1. Shtucer
    16.11.2017 20:10

    Мне в голову пришла аналогия

    Лет на 25 бы пораньше, написали бы свой вим… или, хотя бы книжку "Practical Vim".


    Или например в моем конфиг файле можно найти замечательную строчку:
    ve"aydeBvE"by

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


  1. lynch513
    17.11.2017 19:34

    Можно упомянуть еще про команду точка с запятой
    ; — Повтор предыдущего перехода к позиции командой f[a-z] или F[a-z].

    Бывает удобно использовать с командой точка (. — повтор последней команды изменения текста). Для того, чтобы быстро повторить последние команды: переход по тексту, изменение текста, просто нажимаем ;.;.;.;.;. мизинцем и безымянным пальцем