Найти в Дзене
Блокнот математика

Рубрика "Секреты Вим". Подробнее о привязках, часть 3: ключи и префиксы

Привет, коллеги. Продолжаем вникать в тонкости привязок. Первая часть тут, вторая тут, а сегодня обсудим ключи, позволяющие настроить поведение привязки, и префиксы, дающие возможность привязкам не конфликтовать. Рассмотрим ключи, то есть модификаторы, позволяющие изменить поведение команд типа map. Они ставятся сразу после команды, перед определяемой клавишей/комбинацией и имеют вид <buffer>. Обсудим их. Ключ <buffer> означает, что привязка локальна для буфера. Это полезно, если у вас много разнородных файлов открыто. Вот пример: let @n=0 | inoremap <buffer> <CR> <CR><ESC>:let @n=@n+1<CR>i<C-R>n._ В режиме вставки переопределена клавиша ввода. При нажатии на нее увеличивается регистр n и вставляется в начале строки. Добавляется точка и пробел, который здесь изображен символом _. В итоге можно вводить список: 1. один
2. два
3. и так
4. далее В соседнем окне это поведение только мешает. А в данном можно вбрасывать что-то по ходу чтения текста, а нумерация сама будет вестись. Локальны

Привет, коллеги. Продолжаем вникать в тонкости привязок. Первая часть тут, вторая тут, а сегодня обсудим ключи, позволяющие настроить поведение привязки, и префиксы, дающие возможность привязкам не конфликтовать.

Ключи на привязках, что вы так смотрите? (https://image.shutterstock.com/image-photo/keys-hanging-on-clothesline-white-260nw-1364336678.jpg)
Ключи на привязках, что вы так смотрите? (https://image.shutterstock.com/image-photo/keys-hanging-on-clothesline-white-260nw-1364336678.jpg)

Рассмотрим ключи, то есть модификаторы, позволяющие изменить поведение команд типа map. Они ставятся сразу после команды, перед определяемой клавишей/комбинацией и имеют вид <buffer>. Обсудим их.

Ключ <buffer> означает, что привязка локальна для буфера. Это полезно, если у вас много разнородных файлов открыто.

Вот пример:

let @n=0 | inoremap <buffer> <CR> <CR><ESC>:let @n=@n+1<CR>i<C-R>n._

В режиме вставки переопределена клавиша ввода. При нажатии на нее увеличивается регистр n и вставляется в начале строки. Добавляется точка и пробел, который здесь изображен символом _. В итоге можно вводить список:

1. один
2. два
3. и так
4. далее

В соседнем окне это поведение только мешает. А в данном можно вбрасывать что-то по ходу чтения текста, а нумерация сама будет вестись.

Локальные привязки имеют приоритет перед глобальными: если к одной и той же клавише привязаны две разные команды, сработает локальная для буфера.

Ещё этот ключ позволяет удалить привязки в данном буфере.

Ключ <unique> не позволяет переопределять привязку. Если у вас задана привязка, скажем, на <F2> и вы создали новую, старая пропадет. С этим ключом вы получите сообщение об ошибке и можете назначить другую клавишу.

Ключ <expr> трактует правую часть привязки как выражение, которое надо вычислить, а уже его результат работает как обычная правая часть: в режиме вставки это текст, а в нормальном режиме — команды.

Например,

imap pi acos(-1.0)

вместо pi вставит текст acos(-1.0), но мы-то имели в виду другое. Можно так:

imap pi <ESC>:let @p=string(acos(-1.0))<CR>"pPa

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

imap <expr> pi string(acos(-1.0))

Функция string нужна потому, что вещественное число в строку автоматически не преобразуется. А лучше использовать printf, контролируя заодно и точность.

Конечно, число пи так вводить глуповато, а вот текущую дату или время — весьма разумно.

Штука небезопасная, так что заблокирована возможность изменять буферы и команда :normal.

Можно использовать функцию getchar, чтобы получить код следующего введенного символа. Пример из справки:

inoremap <expr> <C-L> nr2char(getchar())

Причем если есть привязка <C-L>x, то Вим будет ждать символа после <C-L>, и если это х, то сработвает вторая привязка, а если нет, то будет выведен символ, как будто ничего и не произошло.

Ключ <silent> предписывает привязке не выводить ничего в командной строке: поиск, замена и всё такое обычно отображается, а можно скрыть. Сообщения от команд, выполняемых в привязке, выводятся все равно, но команды можно выполнять через :silent.

Ключ <nowait> заставляет привязку срабатывать сразу, как он совпала. Например, если есть привязка qq и другая, qqq. Обычно, Вим будет ждать одну секунду, потом примет решение, что qq было привязкой. Если опция timeout сброшена (по умолчанию она выставлена), Вим будет ждать нажатия следующей клавиши. Но вот тут и может пригодиться ключ <nowait>. Время задержки, конечно, можно изменить: timeoutlen задает его в миллисекундах.

Это пригождается, если привязки имеют префиксы? о которых далее. Например, \q или ,q

Ключ <special> включает распознавание спецклавиш в форме <F2>. Обычно они и так распознаются, но в poptions это можно выключить для совместимости или для удобства (ну, может вам по удобно <F задействовать для чего-то), вот в этом случае ключ настаивает на своем.

Ключ <script> по сути запрещает рекурсию, так как допускает, при выполнении привязки, только те привязки, что определены в скрипте и содержат специальный символ <SID>, делающий привязки (и функции) уникальными для скрипта. Скажем, если вне скрипта определена привязка qq, а внутри двух скриптов привязки <SID>qq, то это три разные привязки. При этом один скрипт вполне может использовать привязку другого — но если хочет этого. Ключ <script> это запрещает, позволяя пользоваться только "местными" привязками.

Теперь обсудим префиксы. Когда привязок много и они идут пакетами, несложно "подраться" и одни привязки перезапишут другие. Ключ <special> не спасет, так как при запуске скрипта с привязками ваши привязки не пострадают, но конфликтующие не загрузятся и вообще скрипт вылетит по ошибке, что не очень хорошо.

Но есть возможность указать в левой части, в начале, символ <leader>. Вот прямо так в угловых скобочках. При этом по умолчанию это будет заменено на слеш, то есть привязка

map <leader>q <nop>

сработает как

map \q <nop>

Но можно заменить лидирующий символ на другой, задав переменную (не опцию!) mapleader:

:let mapleader = ","

И тогда команда выше создаст првязку ,q

Можно и локально в буфере использовать <LocalLeader> и переменную maplocalleader.

Значение переменной играет роль при создании привязок, а на уже созданные привязки не влияет. То есть, если у вас возникли конфликты, вы просто меняете значение переменной и создаете набор привязок с другим лидером, и всё.

Пример. У вас есть привязка \q. Скрипт, помогающий вставлять греческие буквы, создал привязку <leader>q, и она конфликтует с вашей. Вы задаете переменную mapleader, положив туда ; и у вас привязка ;q , которая уже не конфликтует. Вы загрузили скрипт привязок для математических символов, и он тоже норовит создать привязку <leader>q. Что же, вы, перед запуском скрипта, меняете значение переменной на * и получаете *q.

Про уже упомянутый символ <SID> мы поговорим отдельно, пожалуй.

Удачи, коллеги!

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