СПРАВОЧНИК ПО VIM - Брам Мооленаар
Введение в данный предмет представлено в разделе 05.3, разделе 24.7 и разделе 40.1 Руководства пользователя Vim.
1. Привязки кнопок
Привязки кнопок используются для изменения значения нажатых кнопок. Наиболее часто привязки используются для назначения функциональной кнопки для выполнения последовательности команд. Например:
:map <F2> a<C-R>=strftime("%c")<CR><Esc>
Эта привязка добавляет текущую дату и время после курсора (используется соглашение <>, см. |<>|).
Vim предоставляет команды для ввода новых привязок, удаления привязок и отображения списка привязок. Различные формы команды "map" и отношения между ними показаны в разделе |привязки-обзор|.
{левая_часть} | обозначает левую часть привязки |
{правая_часть} | обозначает правую часть привязки |
Эти команды применяются для назначения строки символов в качестве привязки для указанной кнопки или последовательности нажатий кнопок. Их можно использовать для назначения функциональных кнопок последовательностям команд, изменения значения разных кнопок и т.д. О сохранении и восстановлении текущих привязок смотрите в справке по команде |:mkexrc|.
Если первым аргументом одной из указанных выше команд является слово "<buffer>", то привязки будут иметь только местное по отношению к активному буферу значение. Например:
:map <buffer> ,w /[.,;]<CR>
После ввода такой команды ничто не мешает вам определить такую же привязку с совершенно иным значением в другом буфере:
:map <buffer> ,w /[#&!]<CR>
Привязки, имеющие местное по отношению к буферу значение, имеют приоритет перед аналогичными глобальными привязками. Аргумент "<buffer>" также может быть использован для очистки привязок:
:unmap <buffer> ,w
:mapclear <buffer>
Местные привязки также очищаются при удалении буфера, но не при выгрузке буфера из редактора. Иными словами, они ведут себя в точности так же, как и значения местных по отношению к буферу опций.
Для определения привязки, которая не должна отображаться в командной строке, используйте в качестве первого аргумента "<silent>". Например:
:map <silent> ,h /Header<CR>
Строка поиска не будет отображаться в командной строке при использовании этой привязки. Однако, сообщения, которые могут появиться в результате выполнения команд, входящих в привязку, не подавляются. Чтобы избавиться также и от таких сообщений, используйте команду ":silent":
:map <silent> ,h :exe ":silent normal /Header\r"<CR>
Приглашения к вводу, например, при выполнении функции inputdialog(), будут выводиться на экран даже в этом случае. Использование "<silent>" в сокращениях возможно, но приводит к отказу от обновления командной строки.
Если в качестве первого аргумента вышеперечисленных команд используется слово "<script>", а команда используется для определения новой привязки или сокращения, то такая привязка будет переопределять символы в {правой_части} с использованием только тех привязок, которые были определены как местные по отношению к сценарию, начиная от "<SID>". Такая возможность используется для того, чтобы избежать влияния привязок, определённых вне сценария (например, если CTRL-V переопределяется в mswin.vim), но в то же время использовать другие привязки, определённые в этом сценарии.
Замечание: ":map <script>" и ":noremap <script>" являются синонимами. Указание "<script>" переопределяет имя команды. Использование ":noremap <script>" является более предпочтительным, поскольку использование вложенных привязок в этом случае по большей части отменено.
Если первым аргументом одной из рассматриваемых команд является слово "<unique>", а сама команда применяется для определения новой привязки или сокращения, то команда завершается неудачно, если такая привязка или сокращение уже существуют. Например:
:map <unique> ,w /[#&!]<CR>
При определении местной привязки также выполняется проверка существования соответствующей глобальной привязки. Например, в данном случае вторая команда будет завершена неудачно:
:map ,w /[#&!]<CR>
:map <buffer> <unique> ,w /[.,;]<CR>
Слова "<buffer>", "<silent>", "<script>" и "<unique>" могут использоваться в любом порядке, но они должны быть указаны непосредственно после имени команды, перед остальными аргументами.
ПРИВЯЗКИ И РЕЖИМЫ VIM
Имеется пять комплектов привязок:
- Для Обычного режима: Используются при вводе команд.
- Для Визуального режима: Используются при вводе команд в том случае, если имеется Визуально выделенная область.
- Для режима ожидания ввода оператора: Используются при ожидании ввода оператора (после ввода команд "d", "y", "c" и т.д.). Например: ":omap { w" позволяет команде "y{" работать как команда "yw", а команде "d{" работать как команда "dw".
- Для режима Вставки. Эти привязки также используются в режиме Замены.
- Для режима Командной строки: При вводе команды, начинающейся с ":" или "/".
Для режима Выделения не существует специального комплекта привязок, вместо них используются привязки Визуального режима, см. |режим_выделения-привязки|.
Особый случай: при вводе числа-приставки для команды Обычного режима отключается привязка нуля. Это позволяет использовать ноль в привязках без нарушения возможности использовать ноль в качестве числа-приставки.
Обзор команд привязок для работы в различных режимах:
команда: | режимы: | ||
Обычный | Визуальный | Ввод оператора | |
:map :noremap :unmap :mapclear | да | да | да |
:nmap :nnoremap :nunmap :nmapclear | да | - | - |
:vmap :vnoremap :vunmap :vmapclear | - | да | - |
:omap :onoremap :ounmap :omapclear | - | - | да |
Вставка | Командная строка | Язык | |
:map! :noremap! :unmap! :mapclear! | да | да | - |
:imap :inoremap :iunmap :imapclear | да | - | - |
:cmap :cnoremap :cunmap :cmapclear | - | да | - |
:lmap :lnoremap :lunmap :lmapclear | да* | да* | да* |
В оригинальном Vi не было отдельных привязок для Обычного режима/Визуального режима/режима Ввода оператора и режима Вставки/режима Командной строки. Поэтому, команды ":map" и ":map!" используются для определения и отображения привязок в нескольких режимах. Для определения привязки только для работы в определенном режиме Vim позволяет использовать команды ":nmap", ":vmap", ":omap", ":cmap" и ":imap".
Для ввода привязки, которая должна работать в Обычном и Визуальном режимах, но не в режиме ожидания ввода Оператора, нужно определить её для всех режимов, а затем отменить определение привязки в соответствующих режимах:
:map xx цололо
:ounmap xx
То же самое касается привязок, которые должны работать только в Визуальном режиме и режиме ожидания ввода оператора, или привязок только Обычного режима и режима ожидания ввода оператора.
Команда ":lmap" задаёт специальную привязку, которая применяется:
- в режиме Вставки
- в режиме Командной строки
- при вводе шаблона поиска
- при вводе команд, которые принимают в качестве аргумента символ текста, например "r" или "f"
- в строке ввода для функции input()
Иными словами, эти привязки используются в тех случаях, когда введённый символ является частью текста в буфере, а не командой Vim. "Язык" не является по сути отдельным режимом, эта группа представлена здесь исключительно ради удобства.
Самый простой способ загрузки набора соответствующих языковых привязок предоставляется опцией 'keymap'. См. раздел |45.5|.
В режиме Вставки и в режиме командной строки привязки могут быть временно отключены по команде CTRL-^. См. |i_CTRL-^| и |c_CTRL-^|. При вводе обычной команды в командной строке (т.е. не шаблона поиска), привязки отключаются до тех пор, пока не будет введена команда CTRL-^. Последнее состояние этого переключателя запоминается отдельно для режима Вставки и ввода шаблона для поиска. Состояние переключателя языковых привязок также используется при вводе символа в качестве аргумента команд типа "f" или "t".
При добавлении привязки ":lmap" включается использование привязок в режиме Вставки и в строке ввода шаблона для поиска.
Языковые привязки никогда не применяются к символам, уже использующимся в других привязках. Они используются исключительно для введённых с клавиатуры символов. Это подразумевает, что языковые привязки уже были отработаны при отработке других привязок.
Использование мультибайтных символов в привязках возможно, но только для всего символа целиком. Вы не можете использовать в привязке только первый байт мультибайтного символа. Это сделано для того, чтобы избежать проблем в случаях, подобным приведённому ниже:
:set encoding=latin1
:imap <M-C> foo
:set encoding=utf-8
Здесь привязка для <M-C> была определена в кодировке latin1, что соответствует байту со значением 0xc3. Если вы измените кодировку на UTF-8, то при вводе символа А (0xea <M-a>) вы получите два байта 0xc3 0xa1. В этом случае нежелательно использовать 0xc3 в привязке, иначе вы не сможете ввести символ А.
При выводе списка привязок в первых двух колонках используются следующие символы:
СИМВОЛ | РЕЖИМ |
<Space> | Обычный, Визуальный и режим ожидания ввода оператора |
n | Обычный |
v | Визуальный |
o | режим ожидания ввода оператора |
! | режимы Вставки и Командной строки |
i | режим Вставки |
l | привязки ":lmap" для режимов Вставки, командной строки и языка. |
c | режим Командной строки |
Непосредственно перед {правой_частью} может также выводиться специальный символ:
* | показывает, что привязка не может быть переопределена |
& | показывает, что привязка может переопределяться только местными по отношению к сценариям привязками |
@ | указывает на местную по отношению к буфера привязку |
Все символы в списке, начиная от первого непробельного символа после {левой_части} до конца строки (или до '|') считается {правой_частью}. Это позволяет {правой_части} заканчиваться пробелом.
Замечание: при использовании привязок для Визуального режима можно применять отметку "'<", указывающую на начало последнего Визуального выделения в активном буфере. |'<|
Обратите внимание, что только CTRL-V является специальным символом, когда речь идёт о привязках и сокращениях. Если опция 'cpoptions' не содержит флаг 'B', то вместо CTRL-V можно также использовать символ обратной косой черты. В этом случае можно в полной мере использовать соглашение <> (см. |<>|). Однако, "<C-V>" не может быть использовано как CTRL-V для экранирования специального значения последующих символов.
Чтобы использовать символ обратной косой черты в привязке или использовать символ обратной косой буквально в {правой_части}, можно воспользоваться специальной последовательностью символов "<Bslash>". Это позволяет избежать необходимости использования двойных обратных косых при использовании вложенных привязок.
Если две привязки начинаются с одной и той же последовательности символов, то при их вводе возникает неоднозначность. Например:
:imap aa foo
:imap aaa цололо
После того, как Vim получит символы "aa", требуется продолжение ввода для определения, какая именно привязка должна быть использована. Это значит, что после ввода "aa" эта привязка не будет разбираться до тех пор, пока не будет введён ещё один символ. Если вы введёте, к примеру, пробел, то будет вставлена последовательность символов "foo" и пробел, но если вы введёте ещё один символ "a", то это приведёт к вставке текста "цололо".
Vi не позволяет использовать неоднозначные привязки.
Использование в {левой_части} символа CTRL-C не допускается. Для CTRL-C нельзя определить привязку. Причиной такого ограничения является необходимость обеспечения доступности команды CTRL-C для прекращения выполнения команды.
Исключение: в версии с графическим интерфейсом для MS-Windows CTRL-C может использоваться в привязках для выполнения команды копирования в системный буфер обмена. В этом случае для прерывания выполнения команды Vim используется CTRL-Break.
Чтобы включить в {правую_часть} пробел, его следует предварять символом CTRL-V (для ввода двух пробелов нужно ввести два символа CTRL-V, по одному на каждый пробел).
Если {правая_часть} должна начинаться с пробела, то можно использовать "<Space>". Для обеспечения обратной совместимости с Vi также можно отказаться от использования соглашения |<>| и предварять {правую_часть} символом CTRL-V (CTRL-V необходимо нажать дважды), но это ухудшает читаемость команды привязки.
Пустую {правую_часть} можно задавать при помощи ввода единственного символа CTRL-V (CTRL-V необходимо нажать дважды), после которого никакой текст не вводится. К сожалению, этим приёмом нельзя воспользоваться в сценарии vimrc.
Более простым методом получения привязки, которая ничего не делает, является использование "<Nop>" в качестве {правой_части}. Этот метод работает только при включённом соглашении |<>|. Например, чтобы быть уверенным, что функциональная кнопка F8 ничего не делает, введите команды:
:map <F8> <Nop>
:map! <F8> <Nop>
Чтобы определить привязку, которая использует переменную "mapleader", необходимо применить специальную строку "<Leader>". Эта строка автоматически заменяется значением переменной "mapleader" при разборе привязки. Если переменная "mapleader" не имеет значения или имеет пустое значение, то вместо неё используется обратная косая черта. Например, команда
:map <Leader>A oдругая строка<Esc>
работает как
:map \A oдругая строка<Esc>
однако, после
:let mapleader = ","
эта команда будет работать как
:map ,A oдругая строка<Esc>
Обратите внимание, что значение переменной "mapleader" используется в момент определения привязки. Изменение значения переменной "mapleader" после определения привязки не влияет на уже определённые привязки.
<LocalLeader> работает так же, как и <Leader>, но при этом используется значение переменной "maplocalleader" вместо значения переменной "mapleader". Переменная <LocalLeader> используется в привязках, определённых как местные по отношению к буферу. Пример использования:
:map <LocalLeader>q \ДелайСейчас
В глобальных модулях следует использовать <Leader>, а в модулях типа файла нужно использовать <LocalLeader>. Переменные "mapleader" и "maplocalleader" могут иметь одно и то же значение. В то же время, если эти переменные имеют разные значения, то это снижает вероятность пересечения глобальных привязок и привязок для модулей типа файла. Например, переменная "mapleader" может иметь значение по умолчанию (символ обратной косой), в то время как значением переменной "maplocalleader" может быть символ подчёркивания.
В сценариях также можно использовать специальное ключевое слово "<SID>" для определения привязок, являющихся местными по отношению к сценарию. Подробнее см. раздел |<SID>|.
Специальное ключевое слово "<Plug>" можно использовать для организации внутренних привязок, которые не должны срабатывать от ввода какой-либо последовательности кнопок. Это может быть полезно при написании модулей, см. раздел |использование-<Plug>|.
Чтобы представить в привязке символ по его десятичному, восьмеричному или шестнадцатеричному коду, можно использовать конструкцию <Char>:
<Char-123> символ 123
<Char-033> символ 27
<Char-0x7f> символ 127
Эта возможность может оказаться полезной при необходимости задать (мультибайтный) символ в файле 'keymap'. Различия между верхним и нижним регистром при указании кода символа игнорируются.
Использование комментариев после данных команд невозможно, поскольку символ '"' считается частью {левой_части} или {правой_части}.
Поскольку символ '|' используется для отделения команды привязки от следующей команды в той же строке, для включения символа '|' в {правую_часть} необходимо прибегнуть к одному из описанных ниже методов. Таких методов существует три:
используется | в том случае, если | пример |
<Bar> | флаг '<' не задан в 'cpoptions' | :map _l :!ls <Bar> more^M |
\| | флаг 'b' не задан в 'cpoptions' | :map _l :!ls \| more^M |
^V| | всегда, в Vim и Vi | :map _l :!ls ^V| more^M |
(символ ^V используется здесь для передачи CTRL-V; чтобы вставить один символ CTRL-V, необходимо дважды нажать CTRL-V; в данном случае нельзя использовать соглашение <> с тем, чтобы написать просто "<C-V>").
Если значение опции 'cpoptions' соответствует принятому по умолчанию, то работоспособны все три метода.
Если флаг 'b' включён в значение опции 'cpoptions', то "\|" будет распознаваться как признак завершения привязки, которая заканчивается символом '\', после чего следует другая команда. Такое поведение совместимо с Vi, хотя оно и непоследовательно по сравнению с другими командами.
Если ваша привязка содержит команду Ex, то для её исполнения необходимо ввести в конце команды символ завершения строки. Рекомендуется использовать для этой цели <CR>, см. |<>|. Например:
:map _ls :!ls -l %<CR>:echo "конец"<CR>
Чтобы избежать использования в привязках символов, которые вводятся в режиме Вставки или в режиме Командной строки, следует сначала ввести CTRL-V. Привязки в режиме Вставки отключаются при включении опции 'paste'.
Обратите внимание, что при возникновении ошибки (которая приводит к выдаче сообщения об ошибке или подаче звукового сигнала) остальная часть привязки не выполняется. Такое поведение является Vi-совместимым.
Заметим также, что второй символ (аргумент) команд @zZtTfF[]rm'`"v и CTRL-V не привязывается. Это сделано для того, чтобы обеспечить возможность использования всех именных регистров и отметок даже в том случае, если была определена привязка с тем же самым именем.
Чтобы определить привязку, прежде всего необходимо выбрать кнопку или последовательность кнопок, которые будут использоваться в {левой_части}. Вам следует избегать кнопок, которые используются для команд Vim, иначе вы не сможете больше воспользоваться этими командами. Вот несколько советов:
- Используйте функциональные кнопки <F2>, <F3> и т.д. Также можно использовать функциональные кнопки совместно с кнопкой <Shift>: <S-F1>, <S-F2> и т.д. Обратите внимание, что кнопка <F1> уже используется для вызова справочника.
- Используйте метакнопки (с нажатой кнопкой ALT).
- Используйте символ '_' или ',' перед другим символом. Хотя команды "_" и "," существуют в Vim (см. |_| и |,|), маловероятно, что вы будете их использовать.
- Используйте кнопку, которая является синонимом другой команды. Например: CTRL-P и CTRL-N. Чтобы позволить определение большего количества привязок, используйте дополнительный символ.
Файл "index" содержит список всех кнопок, которые не используются и могут быть задействованы в привязках без потери встроенных в Vim возможностей. Вы также можете использовать команду ":help {кнопка}^D", чтобы установить не используется ли эта кнопка в другой команде. (здесь {кнопка} это кнопка, о которой необходимо получить информацию, а ^D это CTRL-D).
В примерах привязок, приведённых ниже, команды вводятся так как написано; например, "<CR>" вводится как четыре отдельных символа. Чтобы это работало, флаг '<' должен быть исключён из значения опции 'cpoptions'.
:map <F3> o#include
:map <M-g> /foo<CR>cwцололо<Esc>
:map _x d/END/e<CR>
:map! цц цололо
Vim сравнивает введённые символы с начальными последовательностями определённых привязок. Если имеется неполное соответствие, то Vim будет ожидать ввода дополнительных символов, пока ввод не будет соответствовать полному соответствию или не будет точно установлено, что такая привязка не определена. Например, если выполнить map! для последовательности "цц", то при вводе первого символа "ц" он не будет появляться на экране до тех пор, пока не будет введён второй символ. Так происходит потому, что Vim не может знать заранее, будет ли следующий символ буквой "ц" или нет. Если включена опция 'timeout' (по умолчанию: включена), то Vim будет ждать ввода следующего символа в течение одной секунды (или заданный в значении опции 'timeoutlen' интервал времени), после чего принимает решение, что введённый символ "ц" должен быть вставлен в текст как есть. Если вы медленно набираете или ваша система тормозит, то опцию 'timeout' можно отключить. В этом случае вы можете также включить опцию 'ttimeout'.
Существует возможность, что те или иные коды кнопок могут не распознаваться в привязках:
- Если Vim может прочесть коды кнопок только частично, как правило только первый символ. Это может происходить в xterm на некоторых версиях Unix.
- Код кнопки помещён после символа или символов, которые использованы в привязке. Например, "<F1><F1>" или "g<F1>".
В этих случаях код кнопки не может быть распознан и привязка работать не будет.
Чтобы избежать подобных проблем, есть два обходных пути:
- Удаление флага 'K' из значения 'cpoptions'. Это заставляет Vim ожидать ввода всех символов кода функциональной кнопки.
- При использовании кнопок от <F1> до <F4> реальный код нажатой кнопки может соответствовать кнопкам от <xF1> до <xF4>. Привязки <xF1> к <F1>, <xF2> к <F2> и т.д. существуют, но они не распознаются после начала привязки.
Убедитесь, что коды кнопок от <F1> до <F4> правильные::set <F1>=<введите CTRL-V><введите F1>
Здесь <F1> вводится как четыре отдельных символа. Кнопки после знака "=" вводятся путём нажатия соответствующих кнопок, а не при помощи буквального текста.
Другим решением для привязки второй специальной кнопки может быть использование реального кода соответствующего символа:
:map <F1><Esc>OP :echo "да"<CR>
Здесь нужно вводить <Esc> как пять символов, поскольку при нажатии реальной кнопки <Esc> Vim будет воспринимать её код и выполнит замену его на <F1>.
Рекурсивной привязкой является привязка, в которой {левая_часть} входит в {правую_часть}. При вводе {левой_части} она заменяется на {правую_часть}, при этом {левая_часть}, встречающаяся в {правой_части}, также будет заменяться на {правую_часть}, и так далее. Это позволяет использовать привязки для бесконечного повторения команд. Такое бесконечно исполнение прекращается только при возникновении ошибки. Примеры таких привязок содержатся в макросах для прохождения лабиринта, входящих в поставку Vim. Имеется также одно исключение: если {правая_часть} начинается с {левой_части}, то первый символ не будет повторно привязываться (такое поведение совместимо с Vi).
Например, команда:
:map ab abcd
позволяет выполнить команду "a" с последующим добавлением текста "bcd". Последовательность "ab" в {правой_части} повторно не привязывается.
Если вы хотите поменять значения двух кнопок, то необходимо воспользоваться командой :noremap. Например:
:noremap k j
:noremap j k
Эти команды приводят к замене команд перемещения курсора вверх и вниз друг на друга.
При использовании обычной команды :map со включённой опцией 'remap', привязка происходит до того места, где обнаружен текст, не являющийся фрагментом {левой_части}.
Например, если вы введёте команды
:map x y
:map y x
то Vim будет заменять x на y, затем y на x и т.д. Если это происходит больше, чем 'maxmapdepth' раз (по умолчанию 1000), то Vim выводит сообщение об ошибке "рекурсивная привязка".
Если в привязку включена команда отмены, то её выполнение будет приводить к возврату текста в то состояние, в котором он находился до выполнения макроса. Такое поведение совместимо с Vi, если речь идёт об единственной команде отмены (две команды отмены не имеют смысла в оригинальном Vi, поскольку это приводит к восстановлению текста в то же состояние, в котором он находился до выполнения первой команды отмены).
Существует три способа задания привязки для специальной кнопки:
- Vi-совместимый метод: привязывается код кнопки; зачастую таким кодом является последовательность, которая начинается с <Esc>. Для ввода такой привязки после набора ":map" необходимо нажать CTRL-V перед нажатием необходимой функциональной кнопки. Заметим, что если код кнопки прописан в termcap (опциях t_), то он автоматически будет переведён во внутренний программный код, т.е. в действительности используется второй метод (см. ниже), если флаг 'k' отсутствует в значении опции 'cpoptions'.
- Второй метод заключается в использовании внутреннего программного кода функциональной кнопки. Для ввода такой привязки наберите CTRL-K и затем нажмите необходимую функциональную кнопку, либо используйте формат "#1", "#2", .. "#9", "#0", "<Up>", "<S-Down>", "<S-F7>" и т.д. (см. таблицу кнопок в разделе |коды_клавиш|, можно использовать все кнопки, начиная с <Up>). Первые десять функциональных кнопок могут быть заданы двумя способами: либо при помощи номера кнопки, например "#2", либо при помощи "<F>", например "<F2>". Оба примера ссылаются на вторую функциональную кнопку. Запись "#0" указывает на функциональную кнопку 10, заданную значением опции 't_f10', которая на некоторых клавиатурах может быть представлена в виде нулевой функциональной кнопки. Формат <> не может быть использован, если значение 'cpoptions' включает флаг '<'.
- При помощи записи в termcap, в формате <t_xx>, где "xx" это имя записи в termcap. Можно использовать любую строковую запись. Например,
:map <t_F3> G
привязывает функциональную кнопку 13 к символу "G". Этот метод работает только в том случае, если значение 'cpoptions' не включает флаг '<'.
Преимущество второго и третьего методов состоят в том, что привязка будет работать без изменений на различных терминалах (функциональная кнопка будет автоматически переводиться в один и тот же внутренний код независимо от типа используемого терминала. При этом необходимо, чтобы termcap был настроен правильно и должны использоваться одни и те же привязки).
ПОДРОБНОСТИ: При получении ввода Vim прежде всего проверяет, не является ли полученная последовательность символов привязкой. Если такая привязка не обнаружена, то затем проверяются соответствующие терминальные коды (см. раздел |терминал-опции|). Если соответствующий терминальный код обнаружен, то он заменяется внутренним программным кодом. В этом случае проверка привязки выполняется снова, поскольку вы могли определить другую привязку для внутреннего кода. При записи файла сценария привязки записываются так, как они распознаются. Если был обнаружен терминальный код, то в сценарий записывается непосредственно терминальный код кнопки. Если терминальный код распознаётся, то в сценарий записывается внутренний код.
2. Сокращения
Сокращения могут применяться в режиме Вставки, режиме Замены и в режиме Командной строки. При вводе слова, являющегося сокращением, оно заменяется на значение сокращения. Это может применяться для облегчения ввода очень длинных слов или автоматического исправления очевидных опечаток.
Например:
:iab ms MicroSoft
:iab tihs this
Существует три типа сокращений:
полноключевые |
сокращения этого типа полностью состоят из символов, которые могут входить в состав ключевых слов (в соответствии со значением опции 'iskeyword'). Это наиболее часто встречающийся тип сокращений. Примеры: "foo", "g3", "-1" |
конечноключевые |
сокращения этого типа заканчиваются на символ ключевого слова, но остальные символы не обязательно являются символами, входящими в состав ключевых слов. Примеры: "#i", "..f", "$/7" |
неключевые |
сокращения этого типа заканчиваются символом, не входящим в состав ключевого слова, а остальные символы могут быть любыми, кроме пробела и символа табуляции. Примеры: "def#", "4/7$" |
Примеры строк, которые не могут быть использованы в качестве сокращений: "a.b", "#def", "a b", "_$r".
Сокращения распознаются только после вводе символа, не входящего в состав ключевого слова. Это может быть в том числе и символ <Esc>, прекращающий режим вставки или символ <CR>, завершающий ввод команды. Неключевой символ, завершающий сокращение, вставляется после подстановки значения сокращения. Исключением является символ <C-]>, который применяется для подстановки значения сокращения без последующей вставки какого-либо символа.
Например:
:ab пп привет
- "пп<Space>" заменяется на "привет<Space>"
- "пп<C-]>" заменяется на "привет"
Символы, набранные перед курсором должны соответствовать сокращению. Каждый тип также имеет свои особые правила:
полноключевые | Перед соответствием должен находиться символ, не входящий в состав ключевого слова, либо слово должно находиться в начале строки или в начале вставки. Исключение: если сокращение определено как единственный символ, то оно не распознаётся как сокращение, если перед ним находится неключевой символ, кроме пробела или <Tab>. |
конечноключевые | Перед началом соответствия должен находится символ ключевого слова, пробел или <Tab>, либо сокращение должно находиться в начале строки или в начале вставки. |
конечноключевые | Перед началом соответствия должен быть символ пробела, <Tab>, либо сокращение должно находиться в начале строки или в начале вставки. |
Примеры: (здесь {КУРСОР} это позиция, где вы вводите символ, не входящий в состав ключевого слова)
:ab foo цололо
" foo{КУРСОР}" | заменяется на " цололо" |
" foobar{КУРСОР}" | не заменяется |
"barfoo{КУРСОР}" | не заменяется |
:ab #i #include
"#i{КУРСОР}" | заменяется на "#include" |
">#i{КУРСОР}" | не заменяется |
:ab ;; <endofline>"
"test;;" | не заменяется |
"test ;;" | заменяется на "test <endofline>" |
Чтобы избежать подстановки сокращения в режиме вставки: введите часть сокращения, затем завершите режим Вставки при помощи <Esc>, после чего вновь перейдите в режим Вставки при помощи команды "a" и продолжите ввод текста. Вы также можете нажать CTRL-V перед символом, который следует после сокращения.
Чтобы избежать подстановки сокращения в режиме Командной строки: нажмите CTRL-V дважды в середине сокращения. CTRL-V перед обычным символом в большинстве случаев игнорируется.
После вставки сокращения можно переместить курсор, например:
:iab if if ()<Left>
Это не будет работать, если в значении 'cpoptions' используется флаг '<'. |<>|
При помощи сокращений можно делать и более сложные вещи. Например, чтобы удалить пробел, введённый после подстановки значения сокращения, можно определить специальную функцию и использовать её внутри сокращения:
func Eatchar(pat)
let c = nr2char(getchar())
return (c =~ a:pat) ? '' : c
endfunc
iabbr <silent> if if ()<Left><C-R>=Eatchar('\s')<CR>
По умолчанию никаких сокращений в Vim не определено.
Сокращения не могут быть рекурсивными. Вы можете использовать команды вроде ":ab f f-o-o" без проблем. Однако, сокращения могут использоваться в привязках.
Vi: в некоторых версиях поддерживаются рекурсивные сокращения без какой-либо веской причины для этого.
При включённой опции 'paste' сокращения не работают.
Точно так же, как и привязки, сокращения могут быть местными по отношению к буферу. Наиболее полезным это свойство является в модулях типа файла, см. раздел |тип_файла-модули|. Например, в модуле для файлов типа исходного кода на языке C можно определить сокращение
:abb <buffer> FF for (i = 0; i < ; ++i)
В правой части сокращения возможно использование специальных символов. Чтобы обойти специальное применение большей части непечатных символов нужно воспользоваться CTRL-V. Количество нажатий CTRL-V зависит от того, как вы собираетесь использовать сокращение. То же самое касается и привязок. Давайте посмотрим, как это выглядит, на следующем примере.
Предположим, вы хотите определить сокращение "esc" для ввода символа <Esc>. При вводе команды ":ab" следует набрать следующее (в данном случае ^V это нажатие CTRL-V, а ^[ это <Esc>):
- Вы вводите: ab esc ^V^V^V^V^V^[
- Всё, что вводится с клавиатуры попадает под разбор экранирования при помощи ^V, поэтому первый, третий и пятый символы ^V необходимы для ввода второго и четвёртого символов ^V и символа ^[ в командной строке.
- Вы видите: ab esc ^V^V^[
- В действительности, командная строка теперь содержит два символа ^V перед символом ^[. Именно так эта команда должна быть введена в файле .exrc, если вы решите использовать этот способ. Здесь первый символ ^V используется для экранирования второго символа ^V; команда :ab использует ^V как собственный символ экранирования, что позволяет экранировать пробел или символ | в сокращении. Команда :ab ничего не делает в отношении символа ^[, поэтому его экранировать не обязательно. В то же время, экранирование символов не может повредить. Именно поэтому ввод семи (но не восьми!) символов ^V также будет работать.
- Сохраняется как: esc ^V^[
- После разбора краткая форма сокращения ("esc") и его полная форма (два символа "^V^[") сохраняются в таблице сокращений. Если вы выполните команду :ab без аргументов, то именно в таком виде и будет отображаться это сокращение.
- После подстановки значения сокращения при вводе "esc" полная форма подвергается тем же преобразованиям, связанным с символом ^V, что и при вводе с клавиатуры. Таким образом, ^V защищает символ ^[ от интерпретации в качестве символа "выхода из режима вставки". Вместо этого выполняется вставка символа ^[ непосредственно в текст.
Заменяется на: ^[
Этот пример сочинил Стив Киркендалл (Steve Kirkendall)
3. Местные привязки и функции
При использовании нескольких сценариев Vim существует опасность, что привязки и функции, определённые в одном сценарии, будут использовать то же имя, что и определённые в других сценариях. Чтобы этого избежать, в Vim есть возможность объявления привязок и функций местными для данного сценария.
Строка "<SID>" может применяться в привязках или в меню. Для её использования необходимо, чтобы флаг '<' отсутствовал в значении 'cpoptions'.
При выполнении команды map Vim заменяет "<SID>" на специальный код кнопки <SNR>, за которым следует уникальный для данного сценария номер и символ подчёркивания. Например,
:map <SID>Add
может определять привязку "<SNR>23_Add".
При определении функции в сценарии к её имени может быть добавлена приставка "s:", которая указывает, что функция является местной по отношению к сценарию. Однако при выполнении привязки вне сценария невозможно узнать, в каком именно сценарии была определена эта функция. Чтобы избежать этой проблемы вместо "s:" лучше использовать "<SID>". При этом выполняется то же самое преобразование, что и для привязок. Это позволяет определять вызов функции в привязках.
При выполнении местной функции, она исполняется в контексте сценария, в котором была определена. Это значит, что все новые функции и привязки, которые определяются в процессе исполнения, также могут использовать "s:" или "<SID>" с тем же самым уникальным номером, что и сама вызванная таким образом функция. Кроме того, для использования становятся доступными местные по отношению к сценарию переменные "s:var".
Исполнение автокоманды или пользовательской команды происходит в контексте сценария, в котором они определяются. Это позволяет команде вызывать местную функцию или использовать местную привязку.
С другой стороны, использование "<SID>" за пределами контекста сценария является ошибкой.
Если вам требуется получить номер сценария для использования в сложном сценарии, можно использовать следующий трюк:
:map <SID>xx <SID>xx
:let s:sid = maparg("<SID>xx")
:unmap <SID>xx
после чего можно удалить "xx" на хвосте.
При выводе списков функций и привязок отображается "<SNR>". Это полезно для отслеживания соответствующих значений.
Команда |:scriptnames| может быть использована для просмотра списка прочитанных сценариев и их номеров <SNR>.
Vi не имеет всех этих возможностей. Кроме того, всё это доступно только в том случае, если Vim скомпилирован с особенностью |+eval|.
4. Команды, определённые пользователем
У вас есть возможность определения собственных команд Ex. Команды, определённые пользователем работают в точности так же, как и встроенные команды, в частности, они могут принимать определённые аргументы, которые могут автодополняться в виде имён файлов или буферов, но при выполнении такой команды она сначала преобразуется во встроенную команду ex и только потом передаётся на выполнение.
Начинающим рекомендуется сначала прочитать раздел 40.2 руководства пользователя.
Все команды пользователя должны начинаться с прописной буквы, чтобы избежать конфликтов со встроенными командами. Некоторые встроенные команды также начинаются с прописной буквы, в частности :Next, :Print и :X, но в таких случаях встроенные команды всегда имеют приоритет перед командами, определёнными пользователем. Остальные символы в пользовательской команде могут быть прописными и строчными буквами или цифрами. При использовании цифр обращайте внимание, что другие команды, которые могут принимать числовой аргумент, могут конфликтовать с вашей командой. Например, команда ":Cc2" может быть как пользовательской командой ":Cc2" без аргумента, так и командой ":Cc" с аргументом "2". Чтобы избежать подобных проблем рекомендуется помещать пробел между именем команды и аргументом.
При вводе пользовательских команд можно использовать сокращённые формы. Однако, если при использовании сокращённой формы возникает неопределённость, то выводится сообщение об ошибке. Более того, встроенные команды всегда имеют приоритет перед командами, определёнными пользователем.
Пример:
:command Rename ...
:command Renumber ...
:Rena " Имеется в виду "Rename"
:Renu " Имеется в виду "Renumber"
:Ren " Ошибка! (неоднозначность)
:command Paste ...
:P " Встроенная команда :Print
В сценариях рекомендуется использовать полные имена пользовательских команд.
Атрибуты команд
Vim работает с командами, определёнными пользователем, точно так же, как и с обычными командами ex. Они могут принимать аргументы или использовать диапазон. Аргументы могут автодополняться как имена файлов, буферов и т.д. Особенности работы пользовательской команды задаётся её атрибутами, которые указываются при определении команды.
Существует несколько атрибутов, которые можно разбить на четыре категории: настройка обработки аргументов, поведение при автодополнении, работа с диапазонами и категория специальных атрибутов. Ниже описаны все доступные атрибуты в соответствии с указанными категориями.
Обработка аргументов
По умолчанию команда, определённая пользователем, не принимает аргументов и при попытке передать команде какой-либо параметр выдаётся сообщение об ошибке. Однако, вы можете указать, что ваша команда должна принимать определённое количество аргументов, при помощи атрибута -nargs. Возможны следующие варианты:
-nargs=0 | Использование аргументов не допускается (по умолчанию) |
-nargs=1 | Требуется ровно один аргумент |
-nargs=* | Допустимо любое количество аргументов (0, 1 или более) |
-nargs=? | Допустимы 0 или 1 аргумент |
-nargs=+ | Требуется как минимум один аргумент |
Аргументы в данном контексте разделяются (неэкранированными) пробелами или символами табуляции.
Обратите внимание, что аргументы являются текстом, а не выражениями. В частности, в качестве "s:var" используется местная переменная по отношению к тому сценарию, где была определена команда, а не к тому, откуда она была вызвана! Например:
script1.vim:
:let s:error = "None"
:command -nargs=1 Error echoerr <args>
script2.vim: >
:source script1.vim
:let s:error = "Ошибка!"
:Error s:error
При выполнении сценария script2.vim будет выведено слово "None", хотя вы скорее всего хотели увидеть слово "Ошибка!". Чтобы выполнить то, что требуется, можно воспользоваться вызовом функции.
Поведение при автодополнении
По умолчанию аргументы пользовательских команд не могут автодополняться, но при помощи одного из перечисленных ниже атрибутов можно задать тот или иной вид автодополнения:
-complete=augroup | группы автокоманд |
-complete=buffer | имена буферов |
-complete=command | команды Ex (и их аргументы) |
-complete=dir | имена каталогов |
-complete=environment | имена переменных окружения |
-complete=event | автокомандные события |
-complete=expression | выражения Vim |
-complete=file | имена файлов и каталогов |
-complete=function | имена функций |
-complete=help | темы справки |
-complete=highlight | группы подсветки синтаксиса |
-complete=mapping | имена привязок |
-complete=menu | меню |
-complete=option | опции |
-complete=tag | метки |
-complete=tag_listfiles | метки, при нажатии CTRL-D отображаются имена файлов |
-complete=var | пользовательские переменные |
-complete=custom,{функция} | специфическое дополнение, заданное при помощи указанной {функции} |
Специфические автодополнения
Вы можете даже использовать собственный вариант автодополнения при помощи атрибута настройки автодополнения "custom,{функция}". Указанная {функция} должна иметь следующий прототип:
:function {имя_функции}(НачалоАргумента, КоманднаяСтрока, ПозицияКурсора)
Функция не обязательно должна использовать все переданные ей параметры, но она должна возвращать возможные варианты автодополнения, разделённые символами новой строки, в виде строкового значения. Для определения контекста автодополнения функция использует переданные ей параметры:
НачалоАргумента | Начальная часть аргумента, который подлежит автодополнению |
КоманднаяСтрока | Полная командная строка |
ПозицияКурсора | Позиция курсора в командной строке |
Вы не обязаны использовать НачалоАргумента для фильтрования возможных вариантов автодополнения. Vim сам выполняет отсев лишних вариантов при помощи встроенного движка регулярных выражений после возврата из функции, что в большинстве случаев оказывается более эффективным.
Следующий пример иллюстрирует использование специальной функции для автодополнения имён пользователей при использовании команды Finger:
:com -complete=custom,ListUsers -nargs=1 Finger !finger <args>
:fun ListUsers(A,L,P)
: return system("cut -d: -f1 /etc/passwd")
:endfun
Работа с диапазонами
По умолчанию, пользовательские команды не допускают указания диапазона строк. Однако, вы можете включить такую возможность при помощи атрибута -range, или использовать определённое числовое значение, либо для указания на номер строки (-range=N, как в команде |:split|), либо в качестве числовой приставки (-count=N, как в команде |:Next|). Возможно использование следующих атрибутов:
-range | Допускается использование диапазона, по умолчанию: текущая строка |
-range=% | Допускается использование диапазона, по умолчанию: весь файл |
-range=N | Число (по умолчанию N) указывает на номер строки (как в команде |:split|) |
-count=N | Число (по умолчанию N) указывает либо на номер строки, либо используется в качестве числовой приставки (как в команде |:Next|). Атрибут -count (без указания значения по умолчанию) работает как -count=0. |
Обратите внимание, что -range=N и -count=N являются взаимоисключающими атрибутами. Вы должны решить какой именно атрибут собираетесь использовать.
Специальные атрибуты
Возможно также применение нескольких специальных атрибутов:
-bang | В команде может использоваться модификатор ! (как в :q или :w) |
-bar | После команды может следовать символ "|" и другая команда. В этом случае использование "|" в аргументе команды становится невозможным. Также выполняется проверка символа ", используемого в качестве символа начала комментария. |
-register | В качестве первого аргумента команды может быть задано необязательное имя регистра (как в командах :del, :put, :yank). |
-buffer | Команда будет доступна только в активном в настоящий момент буфере. |
При использовании атрибутов -count и -register необязательный аргумент, если он задан, удаляется из списка аргументов команды и доступен для использования в тексте команды замены отдельным образом.
Текст команды замены
Команда, на которую заменяется определённая пользователем команда при её выполнении, просматривается на наличие специальных экранированных последовательностей, использующих соглашение о записи <...>. Такие экранированные последовательности заменяются на значения, полученные из введённой командной строки, а весь остальной текст команды замены копируется без изменений. Затем полученная в итоге командная строка передаётся на исполнение как обычная команда Ex. Если первый символ < в экранированной последовательности предваряется символом обратной косой черты, то последовательность копируется в команду без изменений.
Допустимы следующие экранированные последовательности:
<line1> | Начальная строка командного диапазона. |
<line2> | Последняя строка командного диапазона. |
<count> | Любое переданное команде в качестве числового аргумента значение (как описано выше при обсуждении атрибутов '-range' и '-count'). |
<bang> | (См. описание атрибута '-bang') Последовательность заменяется символом ! в том случае, если команда выполняется с модификатором !. В противном случае последовательность заменяется на пустую строку. |
<reg> | (См. атрибут '-register') Заменяется значением регистра, если он указан при выполнении команды. В противном случае заменяется пустой строкой. Синоним этой последовательности: <register>. |
<args> | Аргументы команды в том порядке, в котором они были переданы команде при исполнении, кроме числового аргумента и аргумента, указывающего на имя регистра, которые, как было отмечено выше, не входят в список <args>. |
<lt> | Символ '<' (меньше чем). Эта последовательность необходима для включения буквальной копии одной из указанных выше экранированных последовательностей в текст команды замены. Например, чтобы включить <bang>, используйте <lt>bang>. |
В том случае, если первыми двумя символами экранированной последовательности являются "q-" (например, <q-args>), то значение будет помещено в кавычки с тем, чтобы оно могло быть использовано в выражении. В этом случае аргумент используется как одно значение.
Чтобы позволить командам передавать аргументы определённым пользователем функциям, применяется специальная форма <f-args> ("функциональные аргументы"). Такая форма разбивает аргументы команды в местах появления пробелов и символов табуляции, затем помещает каждый аргумент в кавычки, после чего вся последовательность <f-args> заменяется списком полученных аргументов, разделённых запятыми. Ниже приводится пример команды Mycmd. При отсутствии аргументов последовательность <f-args> также не имеет аргументов.
Примеры:
" Удаление строк, начиная с текущей и до конца
:com Ddel +,$d
" Переименование активного буфера
:com -nargs=1 -bang -complete=file Ren f <args>|w<bang>
" Замена заданного диапазона содержимым файла
" (команду следует вводить в одну строку)
:com -range -nargs=1 -complete=file
Replace <line1>-pu_|<line1>,<line2>d|r <args>|<line1>d
" Подсчёт количества строк в диапазоне
:com! -range -nargs=0 Lines :echo <line2> - <line1> + 1 "lines"
" Вызов функции пользователя (пример использования <f-args>)
:com -nargs=* Mycmd call Myfunc(<f-args>)
При выполнении последней команды в виде
:Mycmd arg1 arg2
Будет вызвана функция
:call Myfunc("arg1","arg2")
:" Более серьёзный пример
:"
:function Allargs(command)
: let i = 0
: while i < argc()
: if filereadable(argv(i))
: execute "e " . argv(i)
: execute a:command
: endif
: let i = i + 1
: endwhile
:endfunction
:command -nargs=+ -complete=command Allargs call Allargs(<q-args>)
Команда Allargs принимает в качестве аргументов любые команды Vim и затем применяет их по отношению ко всем файлам в списке аргументов. Пример использования (обратите внимание на флаг "e" для пропуска сообщений об ошибках и использование команды "update" для записи изменённого буфера):
:Allargs %s/foo/цололо/ge|update
Вызов этой команды приводит к выполнению
:call Allargs("%s/foo/цололо/ge|update")
При определении пользовательских команд в сценарии возможен вызов функций, определённых в качестве местных в пределах этого сценария, а также становится возможным использование местных в пределах этого сценария привязок. При выполнении команды пользователем она будет исполняться в контексте сценария, в котором она была определена. Это становится важным, если в команде используется |<SID>|.