Найти в Дзене
Vim

VimScript 18 [ Сопоставление зависящие от оператора]

Оглавление

| ч17. Сопоставление, оператор ожидания | Содержание | ч19.Строка статуса {status line} |

Идея операторов и перемещений одна из самых важных концепций в Vim, и это одна из главных причин, по которой Vim настолько эффективен. Давайте немного попрактикуемся в определении новых перемещений, потому что изучение этой мощной идеи делает Vim невероятным.

Допустим, вы пишете некоторый текст *.markdown используя для этого язык разметки Markdown. Если вы раньше не использовали Markdown, не волнуйтесь, здесь всё очень просто. Введите следующее:

Первый заголовок.
=========
Это какой-то текст по первой теме.
В нем несколько абзацев.


Второй заголовок.
=========
Это некоторый текст по теме номер два. В нем всего один абзац.

Строки, "подчеркнутые" символами [ = ], рассматриваются Markdown как заголовки. Давайте создадим некоторые сопоставления, которые позволят нам выделять заголовки перемещением. Выполните следующую команду:

:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>

Это сопоставление довольно сложное, поэтому наведите курсор на один из абзацев (не на заголовки) и введите [ cih ]. Vim удалит заголовок раздела в котором вы находитесь, и переведет вас в режим вставки ("изменить содержимое заголовка" {change inside heading}).

Мы использовали то, что никогда раньше не делали, поэтому давайте рассмотрим каждую часть по отдельности. Первая часть сопоставления - [:onoremap ih] это просто команда сопоставления, которую мы видели раньше, поэтому мы пропустим это. <c-u> пока тоже пропустим.

Теперь посмотрим на оставшуюся часть строки:

:execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>

normal

[ :normal ] это команда которая принимает набор символов и выполняет их как если бы они были введены в обычном режиме. Мы рассмотрим её более подробно в следующий раз, мы уже встречались с нею несколько раз, так что пришло время ее испытать. Запустите эту команду:

:normal gg

Vim переместит вас в начало файла. Теперь выполните эту команду:

:normal >>

Vim сделает отступ для текущей строки.

На данный момент не беспокойтесь о [ ! ] после normal, мы позже поговорим о то, что он означает.

execute

[ execute ] Команда принимает строку Vimscript (которую мы рассмотрим более подробно позже) и выполняет ее как команду. Запустите это:

:execute "write"

Vim запишет ваш файл так же, как если бы вы набрали [ :write<cr> ]. Теперь выполните эту команду:

:execute "normal! gg"

Vim переместит вас в начало файла. Но зачем нам делать это, когда мы можем просто запустить [ normal! ] ?

Посмотрите на следующую команду и попытайтесь угадать, что она будет делать:

:normal! gg/a<cr>

Кажется, что это должно сделать следующее:

  • Переместится в начало файла.
  • Запустите поиск.
  • Ввести символ "a" в качестве цели поиска.
  • Нажать return, чтобы начать поиск.

Но Vim лишь переместится в начало файла и больше ничего!

Проблема в том, что [ normal! ] он не распознает "специальные символы", наподобие [ <cr> ]. Есть несколько способов обойти это, но самый простой [ execute ].

Когда [ execute ] просматривает строку на выполнение, которую вы ей указали, перед запуском она заменит все специальные символы. В данном случае [ \r ] это escape-последовательность, которая означает "возврат каретки". Двойная обратная косая черта также является escape-последовательностью, которая помещает обратную косую черту в строку.

Если мы выполним эту замену в нашем сопоставлении и посмотрим на результат, мы увидим, что сопоставление будет выполняться:

:normal! ?^==\+$<cr>:nohlsearch<cr>kvg_
____________________^^^^____________^^^^
______________________||__________________||
Фактически это возвраты каретки, а не четыре символа [ <cr> ]
"левая угловая скобка", "c", "r", и "правая угловая скобка".

Итак, теперь normal! выполнит эти символы так, как если бы мы ввели их в обычном режиме. Давайте разделим их на части, чтобы понять, что они делают:

?^==\+$
:nohlsearch
kvg_

Первая часть [ ?^==\+$ ] выполняет поиск в обратном направлении [?]для любой строки, начинающиеся [ ^ ] с двух или более знаков равенства [==], строчка должна полностью состоять из знаков равенства [ \+$ ] и больше ничего. Это поставит наш курсор на первом символе строки со знаками равенства.

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

Вторая часть - [ :nohlsearch ] это команда просто удаляет выделение поиска из поиска, чтобы он не отвлекал.

Последняя часть представляет собой последовательность из трех команд обычного режима:

  • [ k ]: перемещение вверх по строке. Поскольку мы остановились на первом символе строки со знаками равенства, теперь мы переходим к первому символу текста заголовка.
  • [ v ]: войдите в (символьный) визуальный режим.
  • [ g_ ]: перейти к последнему непустому символу текущей строки. Мы используем его вместо [ $ ] потому что [ $ ]также выделяет символ новой строки, а это не то, что мы хотим.

Результаты

Мы рассмотрели каждую часть сопоставления. Резюмируем:

  • Мы создали сопоставление в операторе ожидания для ("изменить содержимое заголовка" {change inside heading}).
  • Мы использовали execute и normal! для запуска обычных команд, необходимых для выбора заголовка, и получили возможность использование специальных символов.
  • Наше сопоставление выполняет поиск строки со знаками равенства, которая обозначает заголовок, удаляет его и приглашает нас ввести новый заголовок.

Давайте рассмотрим еще одно сопоставление, прежде чем двигаться дальше.

:onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>

Попробуйте поместить курсор в текст раздела и ввести [ cah ]. На этот раз Vim удалит не только текст заголовка, но и строку со знаками равенства которые обозначают заголовок. Вы можете думать об этом движении как "вокруг заголовка этого раздела". {"around this section's heading"})

Чем же отличаются эти сопоставления? Давайте посмотрим:

:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
:onoremap
ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>

Единственное отличие это самый конец строки.

Внутри загаловка (ih) : kvg_
Вокруг загаловка (ah): g_vk0

[ kvg_ ] мы разобрали чуть раньше.

[ g_ ] : перейти к последнему непустому символу в строке.

[ v ] : Переключиться в визуальный режим.

[ k ] : переместиться вверх на одну строку. Так мы перейдем к строке, содержащей текст заголовка.

[ 0 ] : перейти к первому символу строки.

В результате мы получим выделение знаков равенства и название заголовка.

Упражнения

У Markdown также могут быть заголовки, разделенные символами [ - ]. Настройте регулярное выражение в этих сопоставлениях, чтобы оно работало для любого типа заголовка. Возможно, вы захотите прочитать :help pattern-overview. Помните, что регулярное выражение находится внутри строки, поэтому обратные косые черты необходимо экранировать.

Добавьте две автокоманды в свой ~/.vimrc файл, которые создадут эти сопоставления. Убедитесь, что они отображаются только в соответствующих буферах (*.txt), и обязательно cгруппируйте их, чтобы они не дублировались при каждом source ~/.vimrc.

Прочти :help normal.

Прочти :help execute.

Прочти :help expr-quote, чтобы увидеть escape-последовательности, которые вы можете использовать в строках.

Создайте сопоставление в операторе ожидания "следующий адрес электронной почты", чтобы вы могли сказать "изменить адрес электронной почты". Сопоставление [ in@ ] будет хорошим кандидатом для ключа. Возможно вы, захотите использовать /...some regex...<cr> для этого.

| ч17. Сопоставление, оператор ожидания | Содержание | ч19.Строка статуса {status line} |