Привет, коллеги. Бывало ли у вас, что вы забыли переключить раскладку и начали сгоряча набирать текст по-русски латиницей или наоборот? Ну, что-то в таком роде: "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 меня вполне устроит.
Удобная оказалась разработка! Пользуюсь постоянно.
Следующая тема: словари (они же хеши, они же ассоциативные массивы).
Удачи, коллеги!