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

Рубрика "Секреты Вим". Исправление раскладки

Привет, коллеги. Бывало ли у вас, что вы забыли переключить раскладку и начали сгоряча набирать текст по-русски латиницей или наоборот? Ну, что-то в таком роде: "Ghbdtn? Rjkktub!" Или "Ещ иу щк тще ещ иуююю"

Есть программки типа PuntoSwitcher, только для Линукс они если и есть, то не у меня. Да и на Вим вряд ли повлияют — у него своя раскладка.

Я сделал себе свой свитчер: надо нажать на клавишу, но зато не будет дурацких ошибок, вроде как РГО (Российское географическое общество) в строке поиска в браузере исправляется на HUJ и в Википедии открывается соответствующая страница.

Или как-то так.
Или как-то так.

Это пример работы со скриптовым языком: используем переменные, присваивание регистру, функции, списки, извлекаем текст из буфера. Работаем также с привязками.

Всё нижеизложенное надо поместить в файл .vimrc в домашнем каталоге, либо загружать по типу файла, или автокомандами, ну или вызывать вручную через source.

Сначала определим соответствия символов:

let cyr = 'ёйцукенгшщзхъ\фывапролджэячсмитьбю.ЁЙЦУКЕНГШЩЗХЪ|ФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,'
let latin='`qwertyuiop[]\asdfghjkl;''zxcvbnm,./~QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?'

Это просто все символы, что есть на клавиатуре; главное, чтобы были набраны в одном и том же порядке. Естественно, переносы строки выше чисто декоративные: у вас всё должно быть в одну строку. Каждый из двух операторов в одну строку!

Обратите внимание, что строки в одинарных кавычках, в которых все символы (кроме самой одинарной кавычки) означают сами себя. А одинарную кавычку (она во второй команде перед z) надо удвоить, чтобы она означала себя, а не оканчивала строку.

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

Но нам надо ещё выяснить, в какую сторону преобразовывать. Для этого создадим такую функцию:

function! CyrLat(text)
if match(a:text,"[а-я]")>=0
return [g:cyr,g:latin]
else
return [g:latin,g:cyr]
endif
endfunction

Она получит строку text и поищет в ней русские буквы. Если найдет, то вернет список, в котором русская раскладка пойдет первой, а латинская — второй. Если не найдет, то наоборот. Обратите внимание на префиксы переменных: a: для параметров, g: для глобальных переменных.

Собственно преобразование выполнит функция

function! Recode(text)
let L=CyrLat(a:text)
return tr(a:text, L[0], L[1])
endfunction

Она сначала определит, в какую сторону преобразовывать и, собственно, совершит подмену символов, заменяя символы из множества (строки) L[0] соответствующими символами из множества (строки) L[1].

Теперь сделаем привязки. Здесь есть два пути. Можно взять строку, на которой курсор, и преобразовать ее всю:

map <F4> :let @l=Recode(getline('.'))<CR>V"lp

Что мы сделали? По нажатию <F4> мы вызовем функцию Recode, дав ей строку под курсором, которую извлечет функция getline() с параметром '.' (позиция курсора). Последовательность <CR> симулирует нажатие ввода. Результат функции, то есть преобразованная строка, записана в регистр под буквой l (@l). Далее мы выделим всю строку командой V и заменим выделенное на содержимое этого регистра: "lp

Аналогично запишем привязку для режима вставки:

imap <F4> <ESC>:let @l=Recode(getline('.'))<CR>V"lpa

Всё то же самое, только сначала из режима вставки выйдем (<ESC>), а потом опять войдем (a).

Для режима выделения (если вы выделили неправильно введенный текст, чтобы его перекодировать) привязка проще:

vmap <F4> "ld:let @l=Recode(@l)<CR>"lP

Мы удалили выделенное в регистр l ("ld) и содержимое этого регистра (@l) функции и "скормили". Результат опять в регистре, и его вставим справа от курсора, то есть туда, где текст и был.

Недостаток метода в том, что заменяется вся строка (если не выделять текст). А ведь может быть, что все заменять и не надо... Недостаток несколько смягчается наличием привязки vmap, позволяющей перекодировать точно то, что вы хотите.

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

Это всё хорошо, если вы часто выходите из режима вставки (а я выхожу часто). Но возникла ещё одна проблема.

Если вы нажимали <BS> для удаления символов, то всё это останется в регистре. Что-то вроде qwer<80>kb. Это я ввёл qwert<BS>

Это всё преобразуется, и это не то, что мы хотели. А вычистить это безобразие довольно сложно. Да и кроме <BS> есть и еще спецсимволы. Можно, конечно, не вставлять из регистра, а "впечатать", такое есть. Но здесь вторая сложность: надо этот текст выделить и заменить на новый. Делаемо... но я решил остановиться на упрощенном варианте.

Последнее. Несложно сделать ещё и оператор, который будет преобразовывать текст по движению. Сейчас мы можем выделить текст и преобразовать, а так можно будет сделать всё сразу: преобразовать до начала строки, или три слова назад, всё в таком роде.

Лично я не настолько перфекционист, клавиша F4 меня вполне устроит.

Удобная оказалась разработка! Пользуюсь постоянно.

Следующая тема: словари (они же хеши, они же ассоциативные массивы).

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

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