Найти тему
Блокнот математика

Рубрика "Секреты Вим". Умные сокращения

Привет, коллеги! Про сокращения-аббревиатуры уже был материал. Можно определять сокращения, который Вим автоматически раскроет. Например,

:iabbr днк дезоксирибонуклеиновая кислота

И в режиме вставки текст "днк" будет заменен.

Просто забавные аббревиатуры.
Просто забавные аббревиатуры.

Само сокращение может быть трёх типов: из одних лишь словных символов (они перечислены в опции iskeyword); из одних лишь не-словных символов, кроме последнего, который словный; из любых символов, кроме пробела и табуляции, но последним обязательно несловный. В итоге многое можно, в том числе $/7, ..f, def$, 4/7$, но вот a.b нельзя, как и $def, _$r и т.п.

Можно сместить курсор после замены:

:iabbr if if ()<Left>

Помимо abbr, которая создает сокращение для всех режимов (вставки и командной строки), есть iabbr (только вставка) и cabbr (только командная строка). Ещё есть удаление сокращений unabbr, uniabbr, uncabbr. Весь зоопарк есть в Помощи, а я хотел бы сосредоточиться на особом аргументе <expr>. Дело в том, что сокращение можно задать не фиксированным текстом, а выражением, которое будет вычислено и его результат окажется вставлен. Тривиальный пример:

:iabbr <expr> 42 6*9

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

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

Переменная v:char содержит символ, на котором сработало сокращение. Пробел, перевод строки и всё в таком роде.

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

inoremap <expr> <C-L> nr2char(getchar())
inoremap <expr> <C-L>x "foo"

После нажатия ctrl+L ничего не происходит: ожидание символа. Курсор слетит вниз, в командную строку: не бойтесь. Если введете x, то получите текст foo. Если другой символ, то его: функция вернет его код, а nr2char превратит код опять в символ.

Вот практичный пример из Справки:

let counter = 0
inoremap <expr> <C-L> ListItem()
inoremap <expr> <C-R> ListReset()
func ListItem()
let g:counter += 1
return g:counter . '. '
endfunc
func ListReset()
let g:counter = 0
return ''
endfunc

При нажатии ctrl+L мы получим следующий номер, удобно для списков. А ctrl+R позволяет сбросить счет.

А вот пример с сайта vim.fandom.com:

function! Ask(abbr,expansion,defprompt)
let answer = confirm("Expand '" . a:abbr . "'?", "&Yes\n&No", a:defprompt)
" testing against 1 and not 2, I correctly take care of <abort>
return answer == 1 ? a:expansion : a:abbr
endfunction

iabbrev <expr> for Ask('for', "for () {\n}", 2)

Такое сокращение спросит, надо ли ему раскрываться.

Функция confirm позволяет запросить пользователя. Ее первый аргумент есть текст приглашения, а второй задает варианты. Это одна строка, варианты разделяются символом \n, а горячая клавиша отмечается амперсандом (по умолчанию первая буква). Третий аргумент задает выбор по умолчанию, если пользователь нажмет ввод. Если будет нажата клавиша <esc>, то функция вернет нуль. При этом сокращение не раскроется, что и правильно.

Оттуда же, с сайта, почерпнул идею. Можно использовать регистр-выражение и уже упомянутую getchar():

inoremap <expr> date "date".nr2char(getchar())
iтnoremap date^ <c-r>=strftime("%F")<CR>

Так вы можете ввести слово date и следующий символ определит дальнейшее. Если это ^, то сработает сокращение и вы получите текущую дату. Если любой другой символ, всё пойдет без изменений. Здесь мы использовали регистр-выражение = и вставку регистра в текст в режиме вставки <C-R>.

Или так:

iabbr mdy <c-r>=strftime("%B %d, %Y")<CR>

Можно использовать сокращения для исправления частых опечаток и шаблонов вроде for(,,). Всё в ваших руках!

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

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