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

Рубрика "Секреты Вим". Как обойти перехваченное сочетание

Привет, коллеги! Возникла такая проблема: консоль в Убунту на работе перехватывает сочетание <C-V>. А оно нужно иногда: ведь именно оно в режиме вставки позволяет ввести символ по коду или спецклавишу вроде ввода или ESC литерально.

В Виме для этой цели есть дубликат: <C-Q>. Но и его консоль перехватывает самым наглым образом.

Напомню, что <C-V> позволяет ввести код символа, причем делать это можно так:

  1. ввести до трех цифр, которые трактуются как однобайтовый код в десятичной системе. Если нужно две цифры или одну, либо начинайте с нулей, либо введите нецифровой символ после (пробел, например).
  2. Начать с символа o или x (O или X можно тоже) и ввести байт в восьмеричной или шестнадцатеричной системе. Во втором случае цифр не более двух.
  3. Начать с символа u или U и ввести до 4 или до 8 символов (до 4 байт). Второй способ накрывает всю UTF8.

Обходится проблема довольно просто: через функцию nr2char, которая переводит код символа в сам этот символ. Можно так:

:let @q = nr2char(0x20bd)
и потом "qp

Можно использовать регистр-выражение: в режиме вставки в нужном месте нажимаем <C_R>=nr2char(0x20bd)<CR>

Хитрый болт найдется всегда!
Хитрый болт найдется всегда!

Наконец, можно сделать свою привязку с использованием функции input. Она принимает от одного до трех аргументов и позволяет ввести что-то из своей отдельной командной строки. Обязательный аргумент prompt, приглашение: текст, который будет выведен как просьба что-то ввести. Можно задать еще text: текст по умолчанию, и способ автодополнения (если вы вводите имена файлов выражение Вим и всё прочее, что может быть дополнено). Итак:

function GetSymbol()
call inputsave()
let @q=nr2char(input('Code='))
call inputrestore()
endfunction

Это всё вводится в командной строке после двоеточия (перед каждой строкой) или в .vimrc без двоеточий. Отдельно делаем привязку:

:imap <C-F> <ESC>:call GetSymbol()<CR>"qpa

Давайте обсудим, что всё это значит. Функция input открывает пользовательскую строку ввода и ждет, пока пользователь введет что попросили и нажмет ввод. Но всё, что после вызова функции, будет сочтено вводом пользователя! А это нежелательно. Именно поэтому мы не можем поставить всё в одну строку. Вместо этого мы "защищаем" ввод вызовом особой функции inputsave. После всё уже не считается, пока пользователь не скажет своё слово. Отменить этот режим позволяет inputrestore, которых должно быть ровно столько, сколько inputsave.

Содержательная строка одна: мы запрашиваем код, преобразуем его в символ и кладем это в регистр q. Привязка же выходит из режима вставки, вызывает нашу функцию и потом вставляет в текст регистр q. И возвращается в режим вставки.

Можно добавить удобств. Например, шестнадцатеричный код вводить надо с 0x, иначе не получится. Но можно же, чтобы он добавился автоматически:

let @q=nr2char('0x' . input('Code='))

Мы можем развить этот подход и, например, вводить сложные символы, указывая вместе с базовым символом всевозможные модифицирующие (акценты, огласовки и т.п.). Но это уже другая история...

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