Привет, коллеги. Мы уже обсуждали создание собственных команд, которые можно "повесить" на клавиши или последовательности командами семейства map. Можно отдельно создавать команды для разных режимов. Что важно: можно даже в режиме вставки использовать последовательности вроде ;; (редко встречается) или даже qp (может и встретиться, но ввести можно, если сделать паузу между буквами). Можно создавать составные команды, в которых несколько команд выполняются одна за другой: между ними стоит символ |.
Однако такие команды автономны: делают то, что в них прописано. У нас нет возможности указать им, с каким текстом работать. Часто этого довольно: например, команда работает на данной строке, или сама "забирает" текст каким-то движением, или вообще работают со всем текстом.
Можно, правда, выставить метки, и сделать команду, которая будет работать по этим меткам. Но это сложно.
Можно сделать команду командной строки и давать ей диапазон. Но как сделать команду нормального режима, работающую с движением?
Оператором называется команда, которая применяется к движению и работает с указанным текстом. Операторами являются команды y, d, c. А как создавать свои операторы?
Для этого есть простой способ. Есть универсальный оператор g@, который ожидает движение и вызывает некоторую функцию. Она-то и делает то, что вам будет угодно. В том числе и с указанным текстом, который движение определило.
Текст выделяется спецметками [ и ], и потом по ним можно до него добраться. Функция может иметь какое угодно имя (по правилам Вим, имя должно начинаться с заглавной буквы или с префикса) и принимать один параметр (названный тоже как вам будет угодно). Имя этой функции надо поместить в опцию opfunc. Можно это сделать один раз в .vimrc, а можно при привязке, чтобы каждая привязка включала свою функцию.
О функциях будет отдельный материал.
Параметр функции строковой, его значения указывают на тип движения: line для построчного, char для посимвольного, block для визуальных блоков (хотя оператор g@ в визуальном режиме не действует). Это позволяет по-разному обрабатывать текст в разных случаях, хотя это тонко.
Еще раз: текст, выбранный движением, отмечен метками [ и ], и до него можно добраться через них. Вот здесь и можно различать типы движения: если мы прыгнули от середины строки 1 о середины строки 3, то посимвольное и построчное движения суть разные вещи.
Вот пример, совсем несложный, но полезный. Это всё в .vimrc, ввести вручную с командной строки или в файл и выполнить его через :source:
function! RMspaces(type)
:'[,']:s/\s\{2,}/ /g
endfunction
:map ;; :set opfunc=RMspaces<CR>g@
Здесь мы игнорируем тип движения и все движения полагаем построчными. Функция вызывает команду замены двух и более пробелов на один. Но только на строках между метками, а метки для нас любезно ставит универсальный оператор.
Теперь мы можем легко убрать лишние пробелы на:
- текущей строке: ;;$
- до конца документа: ;;G
- на пяти строках ниже: ;;4j
- по поиску: ;;/section
Но вот выделить и применить нельзя. Случай выделения нужно отработать отдельно, создав привязку для этого режима через vmap и предусмотрев для функции вариант работы без параметров. В Справке есть пример. Или просто:
:vmap ;; :s/\s\{2,}/ /g<CR>
Удачи, коллеги!