24,5K подписчиков

Рабрика "Секреты Вим". Позиция в тексте

Привет, коллеги. Сегодня я поделюсь своим опытом. Мне часто приходится работать с текстовой картой морского дна: каждая точка выражена целочисленной двузначной глубиной, а точек очень много: несколько сотен на несколько сотен. По этой карте была построена маска, в которой глубина была заменена на 00 там, где проблем не обнаружено и ** там, где обнаружено. Таких точек, с проблемами, нашлось около ста. Решение по каждой надо принимать лично, алгоритмизировать это сложно.

Фрагмент карты, шрифт 5 пунктов. При работе, конечно, шрифт побольше. Выделены нули, это суша.
Фрагмент карты, шрифт 5 пунктов. При работе, конечно, шрифт побольше. Выделены нули, это суша.

Итак, мне нужно:

  1. найти очередную точку с ** (легко делается через /\*\*)
  2. заменить ее на 00 (легко делается через 2s00<esc>)
  3. запомнить позицию в файле: номер строки и номер "столбца", то есть символа в строке. Числа большие: номера строк трехзначные, номера столбцов вообще четырехзначные.
  4. Прибавить к этим числам константы: дело в том, что в карте несколько первых строк служебные (четыре) и в начале каждой строки идет ее номер (еще четыре символа: три цифры и пробел).
  5. Перейти в другой файл (легко делается через gt) и найти нужную позицию (НОМЕР_СТРОКИ G, НОМЕР_СТОЛБЦА|)
  6. Принять решение, внести исправление и вернуться (gT).

Вопрос в том, как автоматизировать пункты 3-4, а лучше - все с первого по пятый.

Делается это довольно просто. Есть функция getpos, которая с аргументом '.' возвращает позицию курсора в виде списка из четырех элементов: [bufnum, lnum, col, off]

Первый (точнее, "номер нуль", так списки индексируются от нуля) элемент - номер буфера, но там обычно нуль, что означает "этот буфер". Не-нуль там при других аргументах: метках и т.п. Следующие два элемента и есть позиция курсора: строка и столбец, отсчитываются от единицы. Последний элемент нам не нужен: это для режима virtualedit, когда можно поставить курсор за пределы текста.

Итак, p=getpos('.') решает задачу №3.

Прибавить константы тоже несложно:

p[1]=p[1]+4
p[2]=p[2]+4

Помним, что в списке элементы отсчитываются от нуля.

Парная функция называется setpos: она принимает два аргумента. Первым будет '.', то есть позиция курсора, а вторым - тот самый список p:

call setpos('.', p)

Это решает задачу 5.

Собираем всё вместе:

map qq /\*\*<CR>:let p=getpos('.')<CR>2s00<ESC>:let p[1]=p[1]+4<CR>\|:let p[2]=p[2]+4<CR>gt:call setpos('.', p)<CR>

Разберем по частям:

map qq - определяет привязку. По нажатию qq будет срабатывать наш код.

Сначала осуществляем поиск /\*\*<CR>. Символ <CR> означает нажатие клавиши ввода.

Потом запоминание позиции через getpos. Потом замена на нули через режим вставки: 2s00<ESC>

Потом мы модифицируем список. Обратите внимание на конвейер команд \|.

Наконец, мы переходим в соседнюю вкладку (gt) и вызываем там функцию поиска позиции.

Всё.

Потом я немного дополнил команду, вставив gT в начало и запуская привязку из той карты, с которой работал. Тогда диагностический файл мне вообще не нужен, лишь бы был в соседней вкладке. Команда сходит в нее, найдет и запомнит что нужно, вернется, выставит позицию - а дальше моё дело. Так мне надо, помимо собственно экспертного неалгоритмизируемого решения, надо только два движения пальцем сделать, нажав qq.

Это очень удобно оказалось!

Нюанс: это всё работает для однобайтовых символов. Для русского языка, например, нужно немного не так, так как позиция в тексте - байтовая. Но у меня и не было ничего, кроме пробелов и цифр, так что всё хорошо.

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022