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

Метки и специальный поиск

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

Информация по этой теме для начинающих пользователей содержится в разделе 29.1 Руководства пользователя.

  1. Прыжки к меткам
  2. Стек меток
  3. Список соответствий меткам
  4. Подробности о метках
  5. Формат файла меток
  6. Поиск во включённых файлах

1. Прыжки к меткам

Меткой называется слово, которое записано в специальном файле меток «tags». Это слово служит своего рода закладкой, к которой можно быстро переместиться. Например, в программах на языке C каждое имя функции может использоваться в качестве метки. Файл «tags» создаётся отдельной программой, например при помощи ctags, и он должен быть создан, прежде чем вы сможете использовать команды меток.

Курсор перемещается к метке по команде «:tag». Команда CTRL-] позволяет перемещать курсор к метке, на которую ссылается ключевое слово в позиции курсора. Если курсор не находится на ключевом слове, то используется первое ключевое слово справа от курсора.

Команда «:tag» очень полезна при работе с программами на языке C. Если вы хотите посмотреть что делает та или иная функция, достаточно поместить курсор на её имени и нажать CTRL-] : это немедленно переместит вас к месту в коде, где определяется эта функция. Вернуться назад можно по команде CTRL-T. Кроме того, ниже содержится полезная информация об использовании стека меток.

:ta[g][!] {имя}Переход к месту определению указанного {имени}, используя информацию из файла/файлов меток. При этом {имя} помещается в стек меток. Об использовании [!] см. ниже в разделе |метки-!|.
{имя} может быть шаблоном регулярного выражения, см. |метки-регулярные_выражения|. Если {имени} соответствует несколько меток, то выполняется переход к первой метке в списке соответствий. |:tnext|
g<LeftMouse>
<C-LeftMouse>
CTRL-]
Переход к месту определения ключевого слова в позиции курсора. То же, что и :tag {имя}, где в качестве {имени} используется ключевое слово в позиции курсора или после курсора.
Vi: используется ключевое слово после курсора.
{Визуально}CTRL-]То же, что и «:tag {имя}», где в качестве {имени} используется визуально выделенный фрагмент текста.
Vi не имеет такой возможности.

В программе telnet CTRL-] является служебным кодом для вызова приглашения по умолчанию. При вводе CTRL-] для прыжка к метке вместо ожидаемого результата вы можете получить приглашение ввода программы телнет, если используете Vim из сеанса соединения по этому протоколу. Большинство версий телнета позволяют изменять или отключать данный код, о чём подробно написано на странице справочника man по программе telnet. Например, вы можете вызывать эту программу с помощью команды ‘telnet -E {машина}’ для отключения использования кода выхода к приглашению, либо при помощи команды  ‘telnet -e {экранирующий_символ} {машина}’ для использования другого значения этого кода. По возможности используйте другие методы соединения, например «rsh», чтобы избежать подобной проблемы.

В том случае, если обнаружено несколько соответствий метке, используются следующие правила приоритета:

1.«FSC»Полное соответствие статической метке в данном файле.
2.«F C»Полное соответствие глобальной метке в данном файле.
3.«F  «Полное соответствие глобальной метке в другом файле.
4.«FS «Полное соответствие статической метке в другом файле.
5.» SC»Соответствие статической метке в данном файле без учёта регистра.
6.»  C»Соответствие глобальной метке в данном файле без учёта регистра.
7.»   «Соответствие глобальной метке в другом файле без учёта регистра.
8.» S «Соответствие статической метке в другом файле без учёта регистра.

Заметим, что при изменении текущего файла список приоритетов как правило не изменяется, чтобы избежать проблем при вызове команды «:tnext». Однако, список приоритетов изменяется при вызове команды «:tag {имя}».

Соответствия без учёта регистра символов при выполнении команды «:tag» не находятся, если опция ‘ignorecase’ выключена. Однако, даже если эта опция выключена, соответствия, не учитывающие регистр символов, будут обнаружены при использовании шаблона регулярных выражений (начинающегося с символа «/»), в том числе при использовании команды «:tselect». Заметим, что использование регистронезависимого поиска меток отключает бинарный алгоритм поиска по файлу меток, что приводит к снижению эффективности поиска. Этого можно избежать, если отсортировать файл меток с учётом регистра символов. Подробнее об этом написано в справке по опции ‘tagbsearch’.

2. Стек меток

Стек используется для сохранения меток, к которым вы перемещаетесь в процессе работы, вместе с исходными позициями таких перемещений. Метки помещаются в стек только в том случае, если включена опция ‘tagstack’.

g<RightMouse>
<C-RightMouse>
CTRL-T
Прыжок к предыдущей позиции в стеке меток. Возможно использование [числа], определяющего насколько более старую позицию следует использовать для возврата. По умолчанию [число] равно 1.
Vi не имеет такой возможности.
:[число]po[p][!]Прыжок к предыдущей позиции в стеке меток. Возможно использование [числа], определяющего насколько более старую позицию следует использовать для возврата. По умолчанию [число] равно 1.
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:[число]ta[g][!]Прыжок к более новой записи в стеке меток. Возможно использование [числа], определяющего насколько более свежую позицию нужно использовать для возврата. По умолчанию [число] равно 1.
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:tagsКоманда используется для вывода содержимого стека меток. Текущая позиция в стеке отмечается символом ‘>’.
Vi не имеет такой возможности.

Вывод команды «:tags» выглядит примерно следующим образом:

  #  К метке       ОТ   стр.  в файле или тексте
1 1 main 1 harddisk2:text/vim/test
> 2 2 FuncA 58 i = FuncA(10);
3 1 FuncC 357 harddisk2:text/vim/src/amiga.c

В этом списке отображаются метки, к которым вы выполняли переходы, а также позиция курсора перед выполнением прыжка. Более старые метки находятся в верхней части списка, более свежие — ближе к концу списка.

Символ ‘>’ указывает на текущую позицию в стеке. Эта метка будет использоваться при выполнении следующей команды «:tag». Команды CTRL-T и «:pop» будут использовать позиции сверху от текущей метки.

В колонке «К» выводится номер текущего соответствия в списке соответствий. Обратите внимание, что этот номер не изменяется при выполнении команд «:pop»  и «:tag».

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

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

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

Приведём примеры:

«:pop» или CTRL-Tк позиции перед перемещением к предыдущей метке
{число}CTRL-Tк позиции перед перемещением к метке, находящейся в стеке на заданное {число} позиций раньше
«:tag»к более новой метке
«:0tag»к самой последней использованной метке

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

main  --->  FuncA  --->  FuncC
---> FuncB

(Пояснение: функция main вызывает FuncA и FuncB; FuncA вызывает FuncC). Вы можете переместиться из main к определению функции FuncA при помощи CTRL-] при курсоре, помещённом на вызове FuncA. Затем вы можете использовать CTRL-] для перемещения к определению функции FuncC. Чтобы затем вернуться в main, нужно выполнить команду CTRL-T дважды. Затем вы можете аналогичным образом использовать команду CTRL-] для перемещения к определению функции FuncB.

При выполнении команды «:ta {имя}» или CTRL-] соответствующая метка вставляется в текущую позицию стека. Если стек полностью заполнен (его объём ограничен 20 записями), то самая старая запись удаляется, в то время как остальные записи сдвигаются вверх (при этом номер каждой из них в списке уменьшается на единицу). Если последняя использованная запись не находилась внизу стека, то удаляются все записи, расположенные под последней использованной меткой. Это означает, что старая ветка дерева будет потеряна. После выполнения команд, которые мы взяли для примера выше, стек меток может выглядеть следующим образом:

#  К метке      ОТ   стр.  в файле или тексте
1 main 1 harddisk2:text/vim/test
2 FuncB 59 harddisk2:text/vim/src/main.c

При попытке использования пустого стека выводится сообщение об ошибке.

3. Список соответствий меткам

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

:ts[elect][!] [имя]Команда выводит список всех меток, соответствующих указанному имени, используя информацию из файла/файлов меток.
Если [имя] не задано, то используется имя последней использованной метки из стека.
Символ ‘>’ в первой колонке вывода команды указывает на текущую позицию в списке, если такая имеется. В качестве [имени] можно использовать шаблон регулярного выражения,
см. |метки-регулярные_выражения|.
См. также раздел |метки-приоритет|, где описаны значения приоритетов, используемые при выводе.
Vi не имеет такой возможности.
Пример вывода команды:

  # при      тип  метка                    файл
1 F f mch_delay os_amiga.c
mch_delay(msec, ignoreinput)
> 2 F f mch_delay os_msdos.c
mch_delay(msec, ignoreinput)
3 F f mch_delay os_unix.c
mch_delay(msec, ignoreinput)
Введите номер для выбора (или <CR> чтобы отказаться):

Описание колонки «при» приводится в разделе |метки-приоритет|. Обратите внимание, что вывод этой команды зависит от активного в данный момент файла, поэтому выполнение «:tselect xxx» может приводить к разным результатам.
Колонка «тип» содержит информацию о типе метки, если такая информация содержится в файле меток.
В колонке «info» выводится информация, которая может быть найдена в файле меток и зависит от программы, с помощью которой был создан этот файл.
Если список меток слишком длинный, то вам будет предложено приглашение |продолжение_следует|. Если вы уже видите необходимую метку, то можно нажать ‘q’ и ввести соответствующий номер метки.

:sts[elect][!] [имя]Работает как команда «:tselect[!] [имя]», но переход к выбранной метке выполняется в новом окне.
Vi не имеет такой возможности.
g]То же, что и CTRL-], но вместо команды «:tag» используется «:tselect».
Vi не имеет такой возможности.
{Визуально}g]То же, что и «g]», но в качестве имени используется выделенный визуально текст.
Vi не имеет такой возможности.
:tj[ump][!] [имя]То же, что и «:tselect», но при наличии единственного соответствия имени переход к метке выполняется сразу же.
Vi не имеет такой возможности.
:stj[ump][!] [имя]То же, что и «:tjump[!] [имя]», но но переход к метке выполняется в новом окне.
Vi не имеет такой возможности.
g CTRL-]То же, что и CTRL-], но вместо команды «:tag» используется «:tjump».
Vi не имеет такой возможности.
{Визуально}g CTRL-]То же, что и «g CTRL-]», но в качестве имени используется выделенный визуально текст.
Vi не имеет такой возможности.
:[число]tn[ext][!]Переход к следующей соответствующей метке.
[число] указывает на номер соответствия (по умолчанию 1).
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:[число]tp[revious][!]Переход к предыдущей соответствующей метке.
[число] указывает на номер соответствия (по умолчанию 1).
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:[число]tN[ext][!]То же, что и «:tprevious».
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:[число]tr[ewind][!]Переход к первой метке в списке соответствий. Если задано [число], то выполняется переход к метке с соответствующим номером.
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:[число]tf[irst][!]То же, что и «:trewind».
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.
:tl[ast][!]Переход к последней метке в списке соответствий.
[!] обсуждается ниже в разделе |метки-!|.
Vi не имеет такой возможности.

Если при выполнении указанных выше команд не выдаётся иного сообщения, то Vim показывает к какой именно соответствующей метке был выполнен переход и количество меток в списке соответствий:

метка 1 из 3 или более

Фраза «или более» указывает на то, что Vim пока не успел просмотреть все файлы меток. При неоднократном использовании команды «:tnext» или при использовании команды «:tlast» будет найдено больше соответствий.

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

:0tn

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

Список соответствий можно использовать в окне предварительного просмотра. Для этого применяются описанные выше команды с приставкой «p».
Доступно только в том случае, если Vim скомпилирован с особенностью |+quickfix|.

:pts[elect][!] [имя]Выполняет команду «:tselect[!] [имя]» и показывает новую метку в окне «Предпросмотра». Подробнее см. справку по команде |:ptag|.
Vi не имеет такой возможности.
:ptj[ump][!] [имя]Выполняет команду «:tjump[!] [имя]» и показывает новую метку в окне «Предпросмотра». Подробнее см. справку по команде |:ptag|.
Vi не имеет такой возможности.
:[число]ptn[ext][!]«:tnext» в окне предварительного просмотра. См. |:ptag|.
Vi не имеет такой возможности.
:[число]ptp[revious][!]«:tprevious» в окне предварительного просмотра. См. |:ptag|.
Vi не имеет такой возможности.
:[число]ptN[ext][!]То же, что и «:ptprevious».
Vi не имеет такой возможности.
:[число]ptr[ewind][!]«:trewind» в окне предварительного просмотра. См. |:ptag|.
Vi не имеет такой возможности.
:[число]ptf[irst][!]То же, что и «:ptrewind».
Vi не имеет такой возможности.
:ptl[ast][!]«:tlast» в окне предварительного просмотра. См. |:ptag|.
Vi не имеет такой возможности.

4. Подробности о метках

Статической называется метка, определённая для какого-либо специфического файла. В программе на языке C это может быть определение статической функции.

В Vi прыжок к метке приводит к изменению текущего шаблона поиска. Это значит, что после перехода к метке, команды «n», например, не будет выполнять поиск соответствий тому же самому шаблону, что и до перехода. Мы сочли такое поведение глюком, поэтому Vim не заменяет текущий шаблон для поиска при выполнении команды перехода к метке. Несмотря на это, шаблон для поиска метки попадает в историю поиска. Если вам действительно необходимо, чтобы Vim вёл себя в этом отношении как Vi, включите флаг ‘t’ в значение опции ‘cpoptions’.

Vim использует бинарный поиск в файле меток для ускорения поиска необходимой метки (если это включено при компиляции при помощи особенности |+tag_binary|). Однако, бинарный поиск работает только в том случае, если файл меток отсортирован в соответствии со значениями кодов ASCII. По этой причине, если соответствие не было найдено, то повторная попытка выполняется уже с помощью линейного поиска. Если вы хотите использовать только линейный поиск, то вам нужно отключить опцию ‘tagbsearch’. Но лучше всего отсортировать файл меток!

Обратите внимание, что бинарный поиск отключен, если не задано точное имя метки. Это происходит при регистронезависимом поиске и при использовании регулярных выражений, которые не начинаются с фиксированной строки. В этом случае поиск метки может быть намного медленнее. Для ускорения поиска в таких ситуациях следует отсортировать файл меток в соответствии с регистром символов. Подробнее об этом рассказывается в справке по опции ‘tagbsearch’.

Команды «:tag» и «:tselect» могут принимать в качестве параметра регулярное выражение. Список специальных символов, допустимых в регулярных выражениях, приводится в разделе справочника |шаблон|. Если параметр команды начинается с символа ‘/’, то он используется в виде шаблона регулярного выражения. Если параметр не начинается с ‘/’, то он воспринимается буквально, как полное имя метки.

Примеры:

:tag main

переход к метке «main», имеющей наивысший приоритет.

:tag /^get

переход к метке, которая начинается с «get» и имеет наивысший приоритет.        

:tag /norm

выводит список всех меток, содержащих «norm», в том числе «id_norm».

Если аргумент существует как буквальная метка, и в то же время может быть использован в качестве шаблона регулярного выражения, то буквальное соответствие имеет более высокий приоритет. Например, «:tag /open» будет находить «open» перед «open_file» и «file_open».

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

метка в
текущем файле
файл
изменён
!опция autowriteдействие
даxxxпереход к метке
нетнетxxчтение другого файла, переход к метке
нетдадаxтекущий файл бросается без сохранения изменений, чтение другого файла, переход к метке
нетданетвклзапись текущего файла, чтение другого файла, переход к метке
нетданетвыклкоманда не выполняется
  • Если метка находится в текущем файле, то команда выполняется всегда.
  • Если метка находится в другом файле, а текущий файл не содержит несохранённых изменений, то текущим файлом становится файл, в котором находится метка и который загружается в буфер на место старого файла.
  • Если метка находится в другом файле, а текущий файл содержит несохранённые изменения, то при добавлении к команде ! все изменения в текущем файле будут потеряны. Текущим файлом становится файл, в котором находится метка и который загружается в буфер на место старого файла.
  • Если метка находится в другом файле, а текущий файл содержит несохранённые изменения, но опция ‘autowrite’ включена, то перед чтением в буфер файла, в котором находится необходимая метка, изменения в старом файле будут автоматически сохранены.
  • Если метка находится в другом файле, а текущий файл содержит несохранённые изменения, то при отключенной опции ‘autowrite’ команда не будет выполнена. Чтобы сохранить изменения в текущем файле можно воспользоваться командой «:w», после чего можно повторно ввести команду «:tag» без аргумента. Это возможно, поскольку метка попадает в стек уже при первом вызове команды, даже если она завершается неудачно.

Vim запрещает использование некоторых команд по соображениям безопасности. Нечто подобное используется также при использовании опции ‘secure’ для файлов exrc/vimrc в текущем каталоге. См. разделы |о_троянах| и |песочница|.

Если при использовании {адреса_метки} будут внесены изменения в буфер, то будет выведено сообщение:

ПРЕДУПРЕЖДЕНИЕ: команда метки привела к изменению буфера!!!

В будущих версиях изменение буфера с помощью команд меток станет невозможным. Это необходимо по соображениям безопасности. В файле метки можно спрятать нехорошую команду, которую легко не заметить. Например:

:$d|/tag-function-name/

Vi не имеет такой меры предосторожности.

В Vi команда «:tag» при поиске метки устанавливает её имя в качестве последнего использованного шаблона для поиска. В Vim этого не происходит, хотя использованный шаблон и попадает в историю поиска, если в значение опции ‘cpoptions’ не включён флаг ‘t’. Но сам шаблон поиска помещается в историю в любом случае, так что вы можете изменить его, если поиск будет неудачным.

Файлы меток в стиле Emacs поддерживаются в том случае, если Vim скомпилирован со включённой особенностью |+emacs_tags|. Мы не приводим здесь объяснений о файлах меток в стиле Emacs, поскольку эта возможность поддерживается только для обратной совместимости :-).

Значением опции ‘tags’ является список имён файлов. При выполнении команды, работающей с метками, поиск метки происходит в каждом из указанных файлов. Эта опция используется для работы с файлами меток, отличающимися от принятого по умолчанию файла «tags». Она также используется для доступа к общему файлу меток.

Следующий файл в списке меток не используется, если

  • уже найдена соответствующая статическая метка для текущего буфера;
  • уже найдена соответствующая глобальная метка.

Кроме того, на использование файлов меток, заданных в списке, влияет значение опции ‘ignorecase’. Если эта опция выключена, а в файле меток обнаружено только соответствие, не являющееся полным регистрозависимым соответствием, то поиск также будет выполняться в следующем файле меток из списка, пока не будет обнаружено полное регистрозависимое соответствие. Если такая метка не найдена, то используется первое найденное регистронезависимое соответствие. В том случае, если опция ‘ignorecase’ включена и обнаружена соответствующая глобальная метка (с учётом или без учёта регистра символов), то будет использоваться найденная метка, без дополнительных поисков в других файлах меток.

Если имя файла меток начинается с «./», то ‘.’ заменяется на путь к текущему файлу. Это позволяет задать использование файлов меток в том же каталоге, что и текущий файл (независимо от действительного пути к этому каталогу). При помощи «./» вы можете определить порядок файлов меток, в котором осуществляется поиск: сначала в текущем рабочем каталоге («tags,./tags») или сначала в каталоге, где находится текущий файл («./tags,tags»).

Например:

:set tags=./tags,tags,/home/user/commontags

В этом примере поиск метки сначала будет происходить в файле «tags» в том же каталоге, что и текущий файл. Затем будет проверяться файл «tags» в текущем рабочем каталоге. Если метка не будет найдена и в этом файле, то поиск метки будет вестись в файле «/home/user/commontags».

Это поведение может быть изменено для совместимости с Vi путём включения флага ‘d’ в значении опции ‘cpoptions’. В этом случае «./tags» будет указывать на файл меток в текущем рабочем каталоге, а не на файл меток в том же каталоге, где и текущий файл.

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

:set tags=tags\ /home/user/commontags

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

:set tags=tag\\\ file,/home/user/common\\,tags

для файлов «tag file» и «/home/user/common,tags». После выполнения указанной команды опция ‘tags’ будет иметь значение «tag\ file,/home/user/common\,tags».

При включённой опции ‘tagrelative’ (по умолчанию эта опция включена), имена файлов в файле меток в другом каталоге разрешаются относительно каталога, в котором находится файл меток.

5. Формат файла меток

Файл меток может быть создан при помощи внешней программы, например «ctags». В этом файле будут записаны метки для каждой функции. Некоторые версии программы «ctags» также способны создавать метки для макросов «#defined», определений типов typedef, типов enum и т.д.

Программы, которые могут создавать файлы меток:

ctagsИмеется в большинстве систем Unix. Поддерживает только язык C и способна выполнять только самую основную работу.
exuberant ctagsЭто очень хорошая программа. Она работает с языками C, C++, Java, Fortran, Eiffel и другими. Она способна создавать метки для самых разных элементов синтаксиса. См. http://ctags.sourceforge.net.
etagsСвязана с Emacs. Поддерживает много языков.
JTagsДля Java, на Java. Программу можно найти в сети по адресу http://www.fleiner.com/jtags/.
ptags.pyДля Python, на Python. Программа распространяется вместе с исходным кодом Python и ей можно найти в каталоге Tools/scripts/ptags.py.
ptagsДля Perl, на Perl. Программу можно найти в сети по адресу http://www.eleves.ens.fr:8080/home/nthiery/Tags/.
gnatxrefДля Ada. См. http://www.gnuada.org/. Программа gnatxref является частью пакета gnat.

Строки в файле меток должны соответствовать одному из трёх форматов:

  1. {имя_метки}        {TAB} {файл_метки} {TAB} {адрес_метки}
  2. {файл_метки}:{имя_метки} {TAB} {файл_метки} {TAB} {адрес_метки}
  3. {имя_метки}        {TAB} {файл_метки} {TAB} {адрес_метки} {разделитель} {поле} ..

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

Строки в файлах меток могут заканчиваться символом <LF> или символами <CR><LF>. На Макинтоше также работает символ <CR>. Символы <CR> и <NL>  не могут появляться в середине строки.

Второй формат предназначен только для статических меток. Этот формат является устаревшим и вместо него лучше пользоваться третьим форматом. На сегодня он поддерживается только в Elvis 1.x, Vim и некоторыми версиями ctags. Статические метки часто используются для функций, которые являются местными и на которые ссылается только {файл_метки}. Обратите внимание, что оба вхождения {файла_метки} для статической метки должны быть полностью идентичны. См. также описание использования статических меток в разделе |tags-опция|.

Третий формат появился сравнительно недавно. Он включает дополнительную информацию в необязательных полях в конце каждой строки. Кроме того, этот формат обратно совместим с Vi. Он поддерживается только в новых версиях ctags (например, в Exuberant ctags).

{имя_метки}Имя, как правило имя функции, но это может быть любое имя. В имени не может использоваться символ <Tab>.

{TAB}

Одиночный символ <Tab>. 

Замечание: в более ранних версиях допускалось использование любых пробелов на месте {TAB}. Эта практика отменена, чтобы позволить использование пробелов в имени {файла_метки}. Однако, такую возможность можно восстановить, если скомпилировать Vim со включённой особенностью |+tag_any_white|.

{файл_метки}Файл, в котором содержится определение {имени_метки}. Он может иметь как абсолютное, так и относительное путевое имя. В {файле_метки} также можно использовать переменные окружения и маски для подстановки (хотя использование масок выглядит сомнительным). Имя {файла_меток} не может содержать символ <Tab>.
{адрес_метки}Команда Ex, которая выполняет перемещение курсора к метке. Это может быть любая команда Ex, хотя при этом действуют некоторые ограничения (см. |метки-безопасность|). Posix позволяет использовать только наиболее часто употребляемые в этом качестве команды: команды поиска и команды с номером строки.
{разделитель};» Последовательность из символа точки с запятой и символа двойной кавычки.
Эти символы воспринимаются в Vi как начало комментария, что позволяет игнорировать оставшуюся часть строки в этом редакторе. Это позволяет сделать третий формат метки обратно совместимым с Vi.
{поле} ..Список необязательных полей, каждое из которых имеет следующий формат:

<Tab>{имя_поля}:{значение}

{имя_поля} указывает на поле и в нём могут присутствовать только символы латинского алфавита в диапазоне [a-zA-Z].
{значение} может быть любой строкой, не содержащей символ <Tab>.

Следующие символы являются специальными:

«\t»используется вместо <Tab>
«\r»используется вместо <CR>
«\n»используется вместо <NL>
«\\»используется вместо одинарного символа ‘\’

Имеется одно поле, которое не имеет ‘:’. Это поле указывает на тип метки. Оно интерпретируется как если бы это было поле с именем «kind:». Описание различных типов меток содержится в документации к программе ctags.

Единственным полем, которое распознаёт Vim, кроме вышеуказанного, в настоящий момент является поле «file:» (с пустым значением). Оно используется для определения статической метки.

Первые строки файла меток могут начинаться с

!_TAG_

Такие строки сортируются в самое начало файла. Перед такими метками могут идти лишь редкие метки, которые начинаются с «!». Vim распознаёт два вида таких строк. Первая форма строки указывает, что файл был отсортирован. Если такая строка присутствует в начале файла меток, то Vim будет использовать бинарный поиск по данному файлу меток:

!_TAG_FILE_SORTED<Tab>1<Tab>{что-угодно} ~

Файл меток может быть отсортирован в соответствии с регистром символов, что позволяет избежать линейного поиска при включённой опции ‘ignorecase’. Подробнее см. справку по опции ‘tagbsearch’. В этом случае необходимо использовать значение 2:

!_TAG_FILE_SORTED<Tab>2<Tab>{что-угодно} ~

Вторая форма распознаётся только в том случае, когда Vim скомпилирован со включённой опцией |+multi_byte|. Она используется для указания кодировки, используемой в файле меток:

!_TAG_FILE_ENCODING<Tab>utf-8<Tab>{что-угодно} ~

В данном случае в качестве кодировки меток используется «utf-8».  При поиске метки Vim будет автоматически выполнять преобразование из кодировки, заданной значением ‘encoding’, в кодировку файла меток. При выводе списка меток происходит обратное преобразование. Если преобразование не может быть выполнено, то используется непреобразованное значение метки.

В качестве команды может быть использована любая команда Ex, но часто для этого используются команды поиска.

Примеры:

tag1        file1        /^main(argc, argv)/ ~
tag2 file2 108 ~

Команда всегда выполняется с выключенной опцией ‘magic’. В качестве специальных символов в шаблоне поиска используются только «^» (начало строки) и «$» (<EOL>). См. раздел |шаблон|. Обратите внимание, что вы должны экранировать каждый символ обратной косой черты в тексте поиска с помощью символа обратной косой. Это необходимо для обеспечения обратной совместимости с Vi.

                                                                 ** **
Если в качестве команды используется обычная команда поиска (т.е. она начинается с «/» или «?»), то применяется несколько специальных правил:

  • Поиск начинается с первой строки файла.
    Направление поиска при использовании «/» — прямое, а при использовании «?» — обратное.
    Заметим, что значение опции ‘wrapscan’ не играет никакой роли: в любом случае всегда просматривается весь файл целиком.
    Vi использует опцию ‘wrapscan’, что иногда приводит к тому, что метка может быть не найдена.
    Vi начинает поиск со второй строки в другом файле. По этой причине Vi не находит метку в первой строке другого файла при выключенной опции ‘wrapscan’.
  • Если поиск завершается неудачно, то предпринимается повторная попытка поиска без учёта регистра символов. Если же метка не будет найдена и в этом случае, то выполняется поиск
    "^метка[ \t]*("
    

    (т.е. имя метки с приставкой ‘^’ и добавлением «[ \t]*(«). При использовании в качестве метки имени функции это позволяет найти имя функции, если оно начинается с нулевой колонки. Это может быть полезным, если параметры функции изменились с момента создания файла меток. Кроме того, если неудачной окажется и эта попытка, то выполняется ещё один поиск, с использованием

    "^[#a-zA-Z_].*\<метка[ \t]*("
    

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

6. Поиск во включённых файлах

Данные команды выполняют поиск в текущем файле и рекурсивно во всех встреченных включённых файлах. Эта возможность используется для поиска определений переменных, функций и макросов. Если вы желаете выполнить поиск только в текущем файле, то используйте команды, рассмотренные в разделе |шаблоны-поиск|.

Рассматриваемые здесь команды доступны только в том случае, если при компиляции была включена особенность |+find_in_path|.

Если в файле встречается строка, по которой включается другой файл, то прежде чем будет продолжен поиск в активном буфере, будет произведён поиск в этом включённом файле. Если включённый файл не может быть найден, то команда его включения молча игнорируется. Чтобы понять, какие включённые файлы не найдены при выполнении поиска, используйте команду |:checkpath|. Чтобы исправить ситуацию с необнаруженными файлами, возможно придётся значение опции ‘path’.

Замечание: поиск во включённых файлах выполняется в файле, сохранённом на диске, а не в буфере, возможно открытом для редактирования данного файла. Содержимое буфера используется только для поиска в исходном файле.

Строка для поиска может быть любым ключевым словом или определённым макросом. В случае ключевого слова будет найдено любое вхождение слова в тексте. Для определённых макросов будут найдены только строки, в которых встречается соответствие значению опции ‘define’. По умолчанию в качестве значения этой опции используется «^#\s*define», подходящее для исходных текстов программ на языке C. Для других языков программирования это значение может быть изменено. См. пример значения опция для языка C++ в справке по опции ‘define’. Строка не может содержать символ конца строки, поиск выполняется только в пределах строки.

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

Команды, которые начинаются с «[«, выполняют поиск от начала текущего файла.
Команды, которые начинаются с «]», выполняют поиск от текущей позиции курсора.

Опция ‘include’ используется для определения синтаксиса строки, с помощью которой включаются другие файлы. По умолчанию используется «\^#\s*include», что подходит для исходных текстов программ на языке C.

Замечание: Vim не распознаёт синтаксис C, если значению опции ‘include’ соответствует строка внутри «#ifdef/#endif» или внутри комментария — в этом случае поиск в файле всё равно будет выполняться. Опция ‘isfname’ используется для распознавания имени файла, которое может встречаться после соответствия строке, указанной в значении опции ‘include’.

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

Опция ‘comments’ используется в командах, которые отображают единственную строку или выполняют переход к этой строке. Она определяет шаблоны, соответствие которым может использоваться в качестве начала комментария в программном коде. Такие строки игнорируются при поиске, если соответствующая команда не выполняется с использованием модификатора [!]. Имеется одно исключение: если строка соответствует шаблону «^# *define», то она не считается закомментированной.

Если вы желаете посмотреть список соответствий и затем перейти к одному из выбранных элементов списка, то вы можете использовать привязку, которая будет выполнять необходимую работу. Например:

:map <F4> [I:let nr = input("Выберите: ")<Bar>exe "normal " . nr ."[\t"<CR>
[iПоказать первую строку, содержащую ключевое слово в позиции курсора. Поиск начинается с начала файла. Закомментированные строки игнорируются (см. справку по опции ‘comments’). При указании числовой приставки будет показано соответствующая заданному номеру строка, но в этом случае закомментированные строки не игнорируются.
Vi не имеет такой возможности.
]iТо же, что и «[i», но поиск начинается с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]is[earch][!] [число] [/]шаблон[/]То же, что и команды «[i» и «]i», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
[IПоказать все строки, содержащие ключевое слово в позиции курсора. Для каждой найденной строки также отображается имя файла и номер строки. Поиск начинается с начала файла.
Vi не имеет такой возможности.
]IТо же, что и «[I», но поиск начинается с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]il[ist][!] [/]шаблон[/]То же, что и команды «[I» и «]I», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
[ CTRL-IПереход к первой строке, содержащей ключевое слово в позиции курсора. Поиск начинается с начала файла. Закомментированные строки игнорируются (см. справку по опции ‘comment’). При указании числовой приставки будет выполнен переход к строке, соответствующей заданному номеру, но в этом случае закомментированные строки не игнорируются.
Vi не имеет такой возможности.
] CTRL-IТо же, что и «[ CTRL-I», но поиск начинается с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]ij[ump][!] [число] [/]шаблон[/]То же, что и команды «[ CTRL-I»  и «] CTRL-I», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
CTRL-W CTRL-I
CTRL-W i
Открыть файл, содержащий первую строку с ключевым словом в позиции курсора, в новом окне и поместить курсор в эту строку. Поиск начинается с начала файла. Закомментированные строки игнорируются (см. справку по опции ‘comment’). При указании числовой приставки будет выполнен переход к строке, соответствующей заданному номеру, но в этом случае закомментированные строки не игнорируются.
Vi не имеет такой возможности.
:[диапазон]isp[lit][!] [число] [/]шаблон[/]То же, что и команды «CTRL-W i»  и «CTRL-W CTRL-I», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле). Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
[dПоказать первое определение макроса с именем, заданным ключевым словом в позиции курсора. Поиск начинается с начала файла. При указании числовой приставки будет показано соответствие с заданным этим числом номером.
Vi не имеет такой возможности.
]dТо же, что и «[d», но поиск начинается с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]ds[earch][!] [число] [/]строка[/]То же, что и команды «[d» и «]d», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
[DПоказать все определения макроса, содержащие ключевое слово в позиции курсора. Для каждой найденной строки также отображается имя файла и номер строки. Поиск начинается с начала файла.
Vi не имеет такой возможности.
]DТо же, что и «[D», но начиная с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]dl[ist][!] [/]строка[/]То же, что и команды «[D» и «]D», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
[ CTRL-DПереход к первому определению макроса, содержащего ключевое слово в позиции курсора. Поиск начинается с начала файла. При указании числовой приставки будет выполнен переход к строке, соответствующей заданному номеру.
Vi не имеет такой возможности.
] CTRL-DТо же, что и «[ CTRL-D», но начиная с текущей позиции курсора.
Vi не имеет такой возможности.
:[диапазон]dj[ump][!] [число] [/]строка[/]То же, что и команды «[ CTRL-D» и «] CTRL-D», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
CTRL-W CTRL-D
CTRL-W d
Открыть файл, содержащий первую строку с определением макроса, заданного ключевым словом в позиции курсора, в новом окне и поместить курсор в эту строку. Поиск начинается с начала файла. Если задана числовая приставка, то будет выполнен переход к строке, соответствующей заданному номеру.
Vi не имеет такой возможности.
:[диапазон]dsp[lit][!] [число] [/]строка[/]То же, что и «CTRL-W d», но поиск выполняется в заданном [диапазоне] строк (по умолчанию: во всём файле).
Смысл [/] и [!] объясняется ниже.
Vi не имеет такой возможности.
:che[ckpath]Показать список включённых файлов, которые не могут быть найдены.
Vi не имеет такой возможности.
:che[ckpath]!Показать список всех включённых файлов.
Vi не имеет такой возможности.

В перечисленных выше командах допускается использование следующих параметров:

[!]

Использование этого модификатора указывает, что при поиске не следует игнорировать закомментированные строки. Если ! отсутствует, то закомментированные строки (в соответствии со значением опции ‘comments’ или внутри комментариев языка C, т.е. после «//» или внутри /* */) будут пропускаться. Заметим, что соответствие может быть проигнорировано, если строка закомментирована, но сам комментарий заканчивается посередине строки. С другой стороны, если строка является комментарием, но в соответствии со значением опции ‘comments’ Vim не считает строку закомментированной, то соответствие может быть обнаружено. Например:

/* комментарий
цололо */

В этом случае соответствие «цололо» будет найдено, поскольку данная строка не распознаётся как закомментированная, даже несмотря на то, что подсветка синтаксиса правильно рассматривает эту строку как комментарий.

Замечание: поскольку определения макросов редко выглядят как комментарий, модификатор [!] не играет роли в командах «:dlist», «:dsearch» и «:djump».

[/]

Шаблон может быть помещён между символами ‘/’. Если ‘/’ не используются, то выполняется поиск только полных соответствий заданному слову, как при использовании «\<шаблона\>». Добавление следующей команды через ‘|’ возможно только после второго символа ‘/’. Например:

:isearch /строка/ | echo "последний"

В командах «:djump», «:dsplit», «:dlist» и «:dsearch» шаблон используется в качестве обычной строки, а не шаблона для поиска.