Справочник по VIM

Повтор команд, сценарии Vim и их отладка

СПРАВОЧНИК ПО VIM — Брам Мооленаар

Введение в повтор команд можно прочитать в Главе 26 Руководства Пользователя.

  1. Одиночные повторения
  2. Множественные повторения
  3. Сложные повторения
  4. Использование сценариев Vim
  5. Отладка сценариев

1. Одиночные повторения

.Повторное выполнение последнего изменения, с заменой числового параметра на указанное [число]. Если в значении опции ‘cpoptions’ присутствует флаг ‘y’, то эта команда также позволяет повторять операции копирования.

Простые изменения можно повторять с помощью команды «.». Если числовой параметр не указан, то используется [число], которое было указано в команде последнего изменения. Если последнее изменение включало указание на нумерованный регистр, то номер регистра будет увеличен на единицу. Пример использования этой особенности можно посмотреть в разделе |восстановление-регистры|. Обратите внимание, что при повторе команды, которая использует Визуальное выделение, используется область того же РАЗМЕРА — см. |визуальный_повтор|.

@:Повторить последнюю команду из командной строки указанное [число] раз.
Доступно только в том случае, если Vim скомпилирован с особенностью |+cmdline_hist|.

2. Множественные повторения

:[диапазон]g[lobal]/{шаблон}/[команда]Выполнить команду Ex, указанную в параметре [команда] (по умолчанию: «:p») на строках, лежащих в указанном [диапазоне], где имеется соответствие указанному {шаблону}.
:[диапазон]g[lobal]!/{шаблон}/[команда]Выполнить команду Ex, указанную в параметре [команда] по умолчанию: «:p») на строках, лежащих в указанном [диапазоне], где НЕ имеется соответствия указанному {шаблону}.
:[диапазон]v[global]/{шаблон}/[команда]То же, что и :g!.

Глобальные команды работают следующим образом: сначала указанный [диапазон] строк сканируется на соответствие указанному шаблону. Строки, в которых обнаружено соответствие помечаются для дальнейшей работы. При этом, если шаблон занимает несколько строк, то во внимание принимается только начало шаблона.

Далее выполняется указанная [команда] для каждой помеченной строки; иными словами, номер такой строки добавляется к команде. Команды «:v» и «:g» позволяют выполнять указанную команду для каждой непомеченной при первом сканировании строки. При удалении строки её метка исчезает. Значением по умолчанию для [диапазона] является весь буфер (1,$). Выполнение команды может быть прервано по нажатию «CTRL-C». При появлении ошибки в какой-либо строке, выполнение команды для этой строки прерывается, а глобальная команда переходит к следующей помеченной или непомеченной строке.

Для повторения команд, не являющихся командами Ex, можно использовать команду «:normal»:

:g/шаблон/normal {команды}

Убедитесь, что {команды} введены полностью, иначе Vim будет требовать от вас завершения ввода команды при каждом соответствии. При этом экран не будет обновляться и вам не будет видно, что происходит. См. |:normal|.

Команды повтора и восстановления применяются ко всей глобальной команде сразу. Отметка предыдущего контекста будет установлена только один раз (при помощи команды «»» вы сможете вернуться в позицию, где курсор находился перед выполнением глобальной команды.

Глобальная команда устанавливает как последний использованный шаблон поиска, так и последний использованный шаблон замены (такое поведение является Vi-совместимым). Это позволяет осуществлять лёгкую замену строки в глобальном контексте:

:g/шаблон/s//СТРОКА/g

При этом происходит замена всех соответствий шаблону «шаблон» строкой «СТРОКА». Того же эффекта можно достичь при помощи команды:

:%s/шаблон/СТРОКА/g

Это, кстати, на два символа короче!

3. Сложные повторения

q{0-9a-zA-Z»}Записать вводимые символы в указанный регистр {0-9a-zA-Z»} (регистры, указанные в верхнем регистре символов служат для добавления к существующему содержимому). Команда ‘q’ не работает в привязках и не выполняется при воспроизведении команды в регистре.
Vi не позволяет записывать макросы.
qОстановить запись. (Замечание по реализации: ‘q’ в конце записи не сохраняется в регистре, кроме тех случаев, когда она является результатом отработки привязки).
Vi не позволяет записывать макросы.
@{0-9a-z».=*}Воспроизвести содержимое указанного регистра {0-9a-zA-Z».=*} указанное [число] раз. Обратите внимание, что регистр ‘%’ (имя текущего файла) и регистр ‘#’ (имя соседнего файла) не может использоваться. При использовании команды «@=» Vim попросит вас ввести выражение, результат которого будет выполнен. См. также |@:|.
Vi использует только именованные регистры.
@@Повторить предыдущую команду @{0-9a-z»:*} указанное [число] раз.
:[адрес]*{0-9a-z».=}
:[адрес]@{0-9a-z».=*}
Выполнить содержимое регистра {0-9a-z».=*} как команду Ex. При этом курсор помещается на строку с указанным [адресом] (по умолчанию: в текущую строку). Если последняя строка в регистре не имеет символа <CR>, то он автоматически будет добавлен, если в значении опции ‘cpoptions’ присутствует флаг ‘e’.
Обратите внимание, что команда «:*» распознаётся только в том случае, если в значении опции ‘cpoptions’ присутствует флаг ‘*’. Это НЕ является значением по умолчанию, если используется ‘nocompatible’. При использовании «:@=» будет применяться последнее использованное выражение. Результат выражения выполняется как команда Ex. В этих командах привязки не работают.
Vi: возможность предусмотрена только в некоторых версиях.
Возможные изменения в будущем: команда будет выполняться для каждой строки в заданном диапазоне адресов.
:[адрес]@:Повторить последнюю команду из командной строки. Перед выполнением команды курсор помещается в строку с указанным [адресом] (по умолчанию: в текущую строку).
Vi не имеет такой возможности.
:[адрес]@@Повторить предыдущую команду :@{0-9a-z»}. Перед выполнением команды курсор помещается в строку с указанным [адресом] (по умолчанию: в текущую строку).
Vi: возможность предусмотрена только в некоторых версиях.

4. Использование сценариев Vim

Введение в написание сценариев для Vim читайте в Главе 41 Руководства Пользователя.

:so[urce] {файл}Прочитать команды Ex их указанного {файла}. Команды Ex это команды, которые начинаются с «:».
:so[urce]! {файл}Прочитать команды Vim из указанного {файла}. Команды Vim выполняются из Обычного режима путём непосредственного ввода с клавиатуры. Если эта команда выполняется после команд |:global|, |:argdo|, |:windo|, |:bufdo|, а также в цикле или совместно с какой-либо последующей командой, то экран не будет обновляться во время выполнения этих команд.
Vi не имеет такой возможности.
:ru[ntime][!] {файл} ..

Прочитать команды Ex из указанного {файла} в каждом каталоге из списка, указанного в значении опции ‘runtimepath’. Если файл не будет обнаружен, то сообщение об ошибке не выдаётся. Пример:

:runtime syntax/c.vim

Вы можете указать несколько параметров {файл}, разделяя их пробелами. Поиск каждого файла происходит в каталогах в том порядке, в котором они перечислены в значении опции ‘runtimepath’. Для включения пробела в имя файла используйте обратную косую черту (хотя лучше не использовать пробелов в именах файлов).

Если в команде указан [!], то считываются все найденные файлы. Если [!] не указан, то читается только первый найденный файл.

Если в имени {файла} содержатся символы подстановки, то будут найдены все соответствующие файлы. Пример:

:runtime! plugin/*.vim

Именно эту команду Vim использует для загрузки модулей при запуске. Похожая команда

:runtime plugin/*.vim

считывает только первый найденный файл.

Если значение опции ‘verbose’ больше или равно 1, то может быть выдано сообщение об отсутствии файла. Если значение опции ‘verbose’ больше или равно 2, то выдаётся сообщение о каждом найденном файле.
Vi не имеет такой возможности.

:scripte[ncoding] [кодировка]

Указать кодировку символов, используемых в сценарии. Строки сценария будут преобразованы из указанной [кодировки] в кодировку, указанную в значении опции ‘encoding’, в случае, если эти кодировки не совпадают.

Примеры:

scriptencoding iso-8859-5
scriptencoding cp932

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

scriptencoding euc-jp
... строки, подлежащие преобразованию ...
scriptencoding
... строки, не подлежащие преобразованию ...

Если преобразование не поддерживается на вашей системе, то оно не будет выполнено без выдачи сообщения об ошибке.

Не используйте кодировки «ucs-2» и «ucs-4» для написания сценариев. Сценарии не могут быть написаны в этих кодировках, так как символы в них могут содержать байты со значением NUL. Если прочитанный сценарий начинается с отметки порядка байтов BOM (Byte Order Mark) в кодировке utf-8, то Vim сам распознает кодировку. В этом случае команду «:scriptencoding utf-8» можно не использовать.

Команда игнорируется, если Vim собран без особенности |+multi_byte|.
Vi не имеет такой возможности.

:scrip[tnames]Показать все прочитанные сценарии в том порядке, в котором они были прочитаны в первый раз. Имя сценария сопровождается числом, которое используется в качестве идентификатора сценария |<SID>|.
Vi не имеет такой возможности.
Доступно только в том случае, если Vim скомпилирован с особенностью |+eval|.
:fini[sh]Остановить чтение сценария. Эта команда может быть использована только в сценарии Vim. Она позволяет игнорировать продолжение файла. Если эта команда используется между соответствующими друг другу командами |:try| и |:finally|, то перед прекращением считывания выполняются команды, размещённые между «:finally» и соответствующим |:endtry|. Это относится ко всем вложенным «:try» в сценарии. В этом случае, прекращение чтения сценария произойдёт после самой внешней команды «:endtry».
Vi не имеет такой возможности.

Все команды и последовательности команд могут быть помещёны в именованный регистр и затем воспроизведены. Для помещения команд в регистр существует два способа:

  • Можно воспользоваться командой записи «q». При наборе команд происходит их выполнение с сохранением в указанном регистре. Это позволяет вживую наблюдать за тем, что происходит. Если вы допустили ошибку, то можно вставить содержимое регистра в буфер по команде «p», отредактировать командную последовательность, и затем удалить эту команду в тот же самый регистр. Продолжить запись можно путём добавления к прежнему содержимому регистра (для этого надо использовать имя регистра в верхнем регистре символов).
  • Вы также можете удалить или скопировать последовательность команд в регистр.

Часто используемые последовательности команд можно «повесить» на кнопку, используя команду привязки «:map».

С другой стороны, можно поместить команды в отдельный файл и затем выполнить их при помощи команды «:source!». Этот метод выручает при использовании длинных последовательностей команд. При этом также возможно использование команды «:map» для привязки сложных последовательностей к какой-либо кнопке.

Команда «:source» позволяет считывать команды Ex из файла, строка за строкой. Вам придётся вводить с клавиатуры необходимые параметры, если таковые потребуются. Команда «:source!» читает файл сценария символ за символом, воспринимая каждый символ как введённый непосредственно с клавиатуры.

Приведём пример. После выполнения команды «:!ls» вам будет выдано приглашение ввести <Enter> (см. |нажмите-enter|). Если в вашем сценарии имеется строка с командой «!ls», то после выполнения этой строки Vim будет ожидать ввода <Enter> с клавиатуры. В то же время, если вы считываете файл сценария по команде «:source!», а в сценарии имеется строка «!ls», то редактор продолжит чтение файла, пока не будет обнаружен символ <CR>. Поэтому, вам не придётся вводить <CR> с клавиатуры, если только «:!ls» не находится в последней строке файла сценария.

Вы можете помещать команды «:source[!]» в файле сценария, построив таким образом целую иерархию сценариев. Команда «:source» может быть вложена столько раз, сколько это позволяет ограничение на количество открытых одновременно файлов (около 15). Команда «:source!» может быть вложена до 15 раз.

Внутри файла сценария, там, где требуется указать имя файла, можно пользоваться специальной строкой «<sfile>» (вводится буквально, это не название кнопки). Во время чтения файла эта строка будет заменена на имя считываемого файла. Например, если у вас есть файл «other.vimrc» в том же каталоге, что и «.vimrc», то сослаться на него из файла «.vimrc» можно следующим образом:

:source <sfile>:h/other.vimrc

В файлах сценария терминало-зависимые коды клавиш могут быть представлены двухсимвольными терминало-независимыми кодами. Такие сценарии могут быть затем использованы на любых типах терминалов. Первый символ такого кода, 0x80 или 128, на экране отображается как «~@». Второй символ воспроизводится так, как это указано в таблице |коды_клавиш|. Любой такой код можно ввести с помощью команды CTRL-V, за которой следует трёхсимвольный цифровой десятичный код. Учтите, что это можно использовать только в привязках, а НЕ для ввода кодов терминала <t_xx>.

MS-DOS, Win32 and OS/2: Файлы, считываемые при помощи команды «:source», обычно имеют на конце строк символы <CR><NL>. Такое окончание строки работает в этих системах всегда. Если вы используете файл сценария, в котором строка оканчивается на <NL>, например, если этот сценарий перенесён с Unix-системы, то такое окончание строки будет корректно распознаваться в том случае, если значение опции ‘fileformats’ не является пустым, а первая строка не заканчивается на <CR>. Это, однако, может привести к проблемам, если первой строкой в сценарии стоит что-то вроде «:map <F1> :help^M», где «^M» это символ <CR>. В том случае, если первая строка оканчивается на <CR>, а последующие строки нет, будет выдано сообщение об ошибке, поскольку <CR> в первой строке будет удалено.

Macintosh: Файлы, считываемые при помощи команды «:source», обычно имеют в качестве символа конца строки <CR>. Такое окончание строки будет работать на Маке во всех случаях. Если вы используете файл сценария, в котором строка оканчивается на <NL>, например, если этот сценарий перенесён с Unix-системы, то такое окончание строки будет корректно распознаваться в том случае, если значение опции ‘fileformats’ не является пустым, а первая строка не заканчивается на <CR>. Будьте внимательны, чтобы не использовать файл с окончаниями строк на <NL>, в котором первая строка заканчивается на <CR>.

На остальных системах Vim предполагает, что файлы, считываемые по команде «:source», имеют строки, которые заканчиваются на <NL>. Такое окончание строки на этих системах будет работать во всех случаях. Если вы пользуетесь сценарием, в котором строки заканчиваются на <CR><NL>, например, если файл сценария был написан на машине с системой MS-DOS, то во всех строках будет присутствовать лишний символ <CR>, что может привести к проблемам в работе некоторых команд, например, привязок. Автоматическое распознавание символа конца строки <EOL> в этих системах не работает, поскольку часто сценария начинается со строки, определяющей привязку, которая заканчивается на <CR> — это может ввести автоматическое определение символа конца строки в заблуждение.

Длинные строки в файле сценария, содержащего команды Ex, могут быть разбиты на несколько при помощи символа продолжения строки «\» (обратная косая черта), который должен быть помещён в начале следующей строки. Перед символом обратной косой могут находиться пробелы, которые игнорируются.

Например, строки

:set comments=sr:/*,mb:*,el:*/,
\://,
\b:#,
\:%,
\n:>,
\fb:-

интерпретируются так, как если бы это была одна строка:

:set comments=sr:/*,mb:*,el:*/,://,b:#,:%,n:>,fb:-

Все пробельные символы на строке перед обратной косой чертой игнорируются. В то же время, обратите внимание, что пробельные символы в конце предыдущей строки не могут быть вставлены с такой же вольностью; не всегда можно свободно вставлять лишние пробелы в отдельных частях команды.

В командах «:append» и «:insert» существует такая проблема:

:1append
\asdf
.

В данном случае обратная косая черта воспринимается как символ продолжения строки, что в итоге приводит к выполнению команды:

:1appendasdf
.

Чтобы этого избежать, можно добавить флаг ‘C’ к значению опции ‘cpoptions’:

:set cpo+=C
:1append
\asdf
.
:set cpo-=C

Обратите внимание, что если команды находятся внутри функции, то вам потребуется добавить флаг ‘C’ при определении функции:

:set cpo+=C
:function Foo()
:1append
\asdf
.
:endfunction
:set cpo-=C

Пояснение:

Большинство программ понимает символ обратной косой черты в конце строки как указание на продолжение строки. Однако, в Vim это привело бы к нарушению совместимости с Vi. Представьте себе, например, такую привязку Vi:

:map xx  asdf\

Вот почему вместо этого используется необычная обратная косая черта в начале строки.

5. Отладка сценариев

Помимо очевидных сообщений, которые вы можете добавлять в собственные сценарии, чтобы следить за тем, что происходит, Vim предлагает отладочный режим. Этот режим позволяет выполнять команды в считываемых сценариях и пользовательских функциях шаг за шагом, а также устанавливать точки остановки выполнения.

ЗАМЕЧАНИЕ: Режим отладки весьма далёк пока от совершенства. Отладка может вызывать побочные эффекты на работу редактора. Отладкой нельзя пользоваться в некоторых случаях. Например, экран в этом режиме может быть замусорен отладочными сообщениями.
Vi не имеет режима отладки.

В качестве альтернативы режиму отладки, можно использовать разные настройки
опции ‘verbose’. При этом, чем больше значение этой опции, тем более
многословным Vim будет при выполнении команд.

ЗАПУСК ОТЛАДОЧНОГО РЕЖИМА

Для перехода в отладочный режим можно воспользоваться одним из указанных ниже методов:

  1. Запустите Vim с ключом |-D|:

    vim -D file.txt
    

    Отладка начнётся в момент прочтения самого первого файла vimrc. Этот метод будет полезен, если необходимо выяснить, что происходит при запуске Vim.

    Побочным эффектом является то, что в этом случае Vim переключает режим терминала до завершения процесса инициализации, что может привести к непредсказуемым последствиям.

    В версиях, рассчитанных на графический интерфейс (Windows, Macintosh), отладка начинается сразу после открытия окна программы. Чтобы это происходило как можно раньше, поместите в файл vimrc команду :gui.

  2. Выполните необходимую команду с добавлением команды-приставки «:debug». В этом случае отладка включается только на момент выполнения данной команды. Этот способ полезен при отладке какого-либо отдельного сценария или пользовательской функции или для отладки сценариев и функций, которые используются в автокомандах. Например:
    :debug edit test.txt.gz
    
  3. Установите точку остановки выполнения в файле сценария или в пользовательской функции. Это можно сделать прямо в командной строке:

    vim -c "breakadd file */explorer.vim" .
    

    При этом Vim начнёт загружаться и остановится на первой строке сценария «explorer.vim». Точки остановки можно также расставлять и в режиме отладки.

В режиме отладки каждая исполняемая редактором команда будет сначала показана пользователю и только затем выполнена. При этом пропускаются строки комментариев, пустые строки и строки, которые не будут выполняться. Если в строке приводятся две команды, разделенные при помощи «|», то каждая команда будет показана отдельно.

РЕЖИМ ОТЛАДКИ

В режиме отладки можно использовать обычные команды Ex. Например, для просмотра значения переменной:

echo idx

Внутри пользовательской функции будет напечатано значение местной переменной «idx». Для получения значения глобальной переменной можно добавить приставку «g:»:

echo g:idx

Все команды выполняются в контексте текущей функции или сценария. Вы можете также устанавливать значения опций, например изменять значение опции ‘verbose’, если вам желательно, чтобы редактор отображал подробности о том, что происходит, непосредственно в интересующих вас местах:

:set verbose=20

Следует избегать команд, требующих обновления экрана, поскольку их действие не будет заметно до тех пор, пока режим отладки не будет завершён. Например,

:help

никакого полезного результата не принесёт.

В режиме отладки действует отдельная история командной строки.

При работе с функциями номер строки указывается относительно начала функции. Если вам сложно сориентироваться, где вы находитесь, то вам следует открыть файл в другом окне редактора, найти начало функции и опуститься вниз на требуемое число строк, например, по команде «99j» (замените 99 на нужный номер строки).

Кроме того, вам доступны следующие команды:

contПродолжить выполнение до следующей точки остановки.
quitЗакончить выполнение сценария. Эта команда работает так же, как и CTRL-C. Учтите, что некоторые команды будут выполнены даже после ввода этой команды. Выполнение будет остановлено в следующей точке останова.
nextВыполнить команду и вернуться в режим отладки после её выполнения. Эта команда пропускает вызовы функций и чтение других вложенных сценариев.
stepВыполнить команду и вернуться в режим отладки после её выполнения. Эта команда отрабатывает пользовательские функции и считывает вложенные файлы сценариев.
interruptКоманда работает почти так же, как и CTRL-C, но в отличие от «>quit» возвращается в режим отладки после прекращения выполнения команды. Это может быть полезно для отладки обработки исключительных ситуации, в командах |:finally| и |:catch|.
finishЗавершить выполнение текущего сценария или пользовательской функции и вернуться в режим отладки для выполнения следующей за вызовом функции или сценария команды.

О дополнительных командах режима отладки:

  • Автодополнение командной строки для них не предусмотрено, оно выполняется только для обычных команд Ex.
  • Команды можно сокращать до одного символа: «c», «n», «s» and «f».
  • Ввод <CR> вызывает повторение предыдущей дополнительной команды. После выполнения какой-либо другой команды эта возможность отключается, поскольку не ясно, какую именно команду вы хотели бы повторить.
  • Если вы хотите использовать команду Ex с тем же именем, то просто добавьте двоеточие: «:cont», «:next», «:finish» (или более краткие версии).
УСТАНОВКА ТОЧЕК ОСТАНОВКИ
:breaka[dd] func [номер_строки] {имя}

Установит точку остановки внутри функции. Пример:

:breakadd func Explore

Проверка имени функции не выполняется, поэтому точка остановки может быть определена для ещё не написанной функции.

:breaka[dd] file [номер_строки] {имя}Установить точку остановки в файле сценария. Например:

:breakadd file 43 .vimrc

Параметр [номер_строки] указывает на номер строки, в которой или после которой должна произойти остановка в отладочном режиме. Если номер строки не указан, то используется строка 1.

Параметр {имя} является шаблоном, которому соответствует имя файла или функции. Правила составления шаблона такие же, как и для автокоманд. Соответствие шаблону должно быть полным (как если бы шаблон начинался с «^» и заканчивался «$»). Символ «*» соответствует любой последовательности символов. Опция ‘ignorecase’ не используется, но в самом шаблоне можно использовать «\c» для указания, что регистр символов игнорируется (см. |/\c|). Скобки () к имени функции добавлять не следует!

Поиск соответствия для файлов сценариев выполняется по отношению к полному имени файла. Например:

breakadd file explorer

не будет соответствовать нужному файлу, поскольку путь к файлу не указан.

breakadd file *explorer.vim

будет соответствовать файлам «…/plugin/explorer.vim» и «…/plugin/iexplorer.vim».

breakadd file */explorer.vim

будет соответствовать только файлу «…/plugin/explorer.vim».

Поиск соответствия среди функций выполняется по имени функции в той форме, в которой оно выводится по команде «:function». В местных функциях при этом добавляются указатели вроде «<SNR>99_».

УДАЛЕНИЕ ТОЧЕК ОСТАНОВКИ
:breakd[el] {номер}Удалить точку остановки с указанным {номером}. Для уточнения номера необходимой точки остановки используйте команду :breaklist.
:breakd[el] func [номер_строки] {имя}Удалить точку остановки в функции.
:breakd[el] file [номер_строки] {имя}Удалить точку остановки в прочитанном файле.

Если [номер_строки] не указан, то удаляется первая точка остановки в функции или файле.

Указанное {имя} должно быть полностью идентично тому, которое использовалось для команды «:breakadd». Например, шаблоны «explorer», «*explorer.vim» и «*explorer*» являются разными.

ПРОСМОТР СПИСКА ТОЧЕК ОСТАНОВКИ
:breakl[ist]Показать все существующие точки остановки.
КОЕ-ЧТО ЕЩЁ
:debugg[reedy]

Команда позволяет читать команды режима отладки из стандартного потока ввода вместо получения их напрямую от пользователя. Это может быть полезно для тестирования сценариев. Например (набирается в одну строку):

echo 'q^Mq' | vim -e -s -c debuggreedy -c 
'breakadd file script.vim' -S script.vim
:0debugg[reedy]Отмена действия команды «:debuggreedy»: получать команды режима отладки от пользователя, не использовать упреждающего набора при выполнении команд отладки.