РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ VIM - Брам Мооленаар

Собственные правила подсветки синтаксиса

В комплект поставки Vim входят правила для подсветки синтаксиса для пары сотен типов файлов. В этой главе рассказывается о том, что делать в тех случаях, когда вы редактируете файл, правила синтаксиса для которого не входят в комплект поставки. Также смотрите |:syn-определение| в справочнике.

44.1    Основные команды синтаксиса
44.2    Ключевые слова
44.3    Шаблоны соответствий
44.4    Синтаксические области
44.5    Вложенные элементы
44.6    Указание следующих групп для разбора синтаксиса
44.7    Другие аргументы
44.8    Кластеры
44.9    Включение других файлов с правилами синтаксиса
44.10    Синхронизация
44.11    Установка файла синтаксиса в системе
44.12    Переносимый формат файла синтаксиса

Следующая глава: Выбор языка
Предыдущая глава: Использование типов файлов
Содержание: Руководство пользователя Vim


44.1 Основные команды синтаксиса

Вы можете сэкономить время и силы, если начнёте работу с уже существующим файлом синтаксиса. Постарайтесь найти файл с правилами синтаксиса в $VIMRUNTIME/syntax для языка, который похож на используемый в вашем новом типе файла. Кроме того, это поможет вам понять общую структуру файлов правил синтаксиса.

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

:syntax clear

Это не требуется для конечного результата, но сильно поможет в наших экспериментах.

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

СПИСОК ОПРЕДЕЛЁННЫХ ЭЛЕМЕНТОВ

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

:syntax

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

Чтобы посмотреть элементы из определённой синтаксической группы, используйте команду:

:syntax list {имя-группы}

Также этим можно пользоваться и для получения списка кластеров (объясняется в |44.8|). Просто добавьте к имени символ @.

РЕГИСТР СИМВОЛОВ

Некоторые языки не принимают во внимание регистр, например Pascal. Другие языки, например C, различают регистр символов. В правилах следует указывать с каким именно случаем мы имеем дело:

:syntax case match
:syntax case ignore

Аргумент "match" означает, что Vim будет искать строгое регистрозависимое соответствие ключевым словам в синтаксических элементах. В этом случае, "int" будет отличаться от "Int" и "INT". При использовании аргумента "ignore" регистр символов не учитывается: "Procedure", "PROCEDURE" и "procedure" указывают на один и тот же синтаксический элемент.

Команды ":syntax case" могут появляться в любом месте файла правил синтаксиса и оказывают влияние на команды, которые следуют после. В большинстве случаев вам достаточно иметь только одну команду :syntax case в файле синтаксических правил; однако, если вы работаете с необычным языком, который содержит как регистрозависимые, так и регистронезависимые элементы, то вы можете вставлять команды ":syntax case" в файле так, как вам необходимо.


44.2 Ключевые слова

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

:syntax keyword {группа} {ключевое-слово} ...

{группа} это имя синтаксической группы. С помощью команды ":highlight" вы можете присвоить {группе} тот или иной цвет для подсветки. Само ключевое слово задаётся аргументом {ключевое-слово}. Вот несколько примеров:

:syntax keyword xType int long char
:syntax keyword xStatement if then else endif

В этих примерах используются группы "xType" и "xStatement". По соглашению, имя каждой группы начинается с типа файла, для которого определяется данная группа. В нашем примере определены группы для типа файла x. В правилах синтаксиса для сценариев оболочки "csh" мы использовали бы группы вроде "cshType". Таким образом, приставка в имени соответствует значению опции 'filetype'.

Наши примеры позволят выделять слова "int", "long" и "char" одним способом, а слова "if", "then", "else" и "endif" -- другим. Теперь нам осталось только связать имена групп x со стандартными группами Vim. Это выполняется при помощи следующих команд:

:highlight link xType Type
:highlight link xStatement Statement

Теперь Vim будет подсвечивать слова группы "xType" как стандартную группу "Type", а слова группы "xStatement" как стандартную группу "Statement". Имена стандартных групп см. в |имена-групп|.

НЕОБЫЧНЫЕ КЛЮЧЕВЫЕ СЛОВА

Символы, используемые в ключевом слове, должны быть включены в значение опции 'iskeyword'. Если вы используете символ, который не входит в значение этой опции, то слово не будет определено как ключевое. Vim даже не предупредит вас об этом каким-либо сообщением.

Наш язык x использует в ключевых словах символ '-'. Поэтому, введём такие команды:

:setlocal iskeyword+=-
:syntax keyword xStatement when-not

Использование команды ":setlocal" позволяет менять значение опции 'iskeyword' только для текущего буфера. В то же время, изменение значения этой опции также изменяет и поведение таких команд, как "w" и "*". Если это не желательно, то вместо определения ключевого слова потребуется определение шаблона соответствия (объясняется в следующем разделе).

Язык x позволяет также использовать сокращения ключевых слов. Например, "next" можно сокращать до "n", "ne" или "nex". Такое ключевое слово с сокращениями можно определить командой:

:syntax keyword xStatement n[ext]

Ключевые слова всегда совпадают только с целыми словами, так что это не будет соответствовать слову "nextone".


44.3 Шаблоны соответствий

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

:syntax match xIdentifier /\<\l\+\>/

Замечание: Ключевые слова переопределяют значение любого синтаксического элемента. Поэтому, в нашем примере слова "if", "then" и т.д. будут определены как ключевые слова, как это объявлено по команде ":syntax keyword", несмотря на то, что они попадают под действие шаблона для группы xIdentifier.

Заключительная часть команды это шаблон, подобный тем, которые используются в командах поиска. Шаблон помещается внутри пары символов //, как это делается, например, в команде ":substitute". Вы можете пользоваться любыми другими символами, например ++ или "".

Теперь определим шаблон соответствия для комментария. В языке x комментарием считается всё, что угодно, от символа # до конца строки:

:syntax match xComment /#.*/

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


44.4 Синтаксические области

В нашем гипотетическом языке x строки заключены в двойные кавычки ("). Чтобы подсвечивать строки, нам потребуется объявить синтаксическую область. Мы должны указать начало области (двойная кавычка) и конец области (также двойная кавычка). Определение выглядит так:

:syntax region xString start=/"/ end=/"/

Директивы "start" и "end" определяют шаблоны, по которым происходит поиск начала и конца области. Но что делать со строками, которые выглядят так, как показано ниже?

"Строка с двойной кавычкой (\") внутри" ~

Мы столкнулись с проблемой: ведь двойная кавычка в середине строки будет распознаваться как конец синтаксической области. Нам надо также показать редактору, что не нужно обращать внимание на экранированный символ кавычки внутри строки. Это делается с помощью директивы "skip":

:syntax region xString start=/"/ skip=/\\"/ end=/"/

Двойная косая черта соответствует одинарной косой черте, поскольку сама косая черта в шаблонах нуждается в экранировании.

В каких случаях вместо шаблона соответствия необходимо использовать синтаксическую область? Основное различие состоит в том, что шаблон соответствия использует только один шаблон, который должен в точности совпадать. Область же начинается как только встречается совпадение с шаблоном "start". Будет ли найдено соответствие для шаблона "end" или нет -- не имеет никакого значения. Поэтому, если элемент может не включать соответствия для шаблона "end", то использовать область нельзя. В остальном, определение области как правило намного проще и внутри области намного проще находить вложенные элементы, о чём рассказывается в следующем разделе.


44.5 Вложенные элементы

Посмотрите на этот комментарий:

%Get input  TODO: Skip white space ~

Вам хотелось бы подсветить слово TODO жёлтыми буквами, несмотря на то, что оно находится внутри комментария, который подсвечивается синим. Чтобы Vim мог это сделать, надо определить следующие синтаксические группы:

:syntax keyword xTodo TODO contained
:syntax match xComment /%.*/ contains=xTodo

В первой строке мы используем аргумент "contained", который показывает редактору, что данный элемент может существовать только внутри другого синтаксического элемента. В следующей строке есть указание "contains=xTodo". Оно обозначает, что внутри может присутствовать элемент xTodo. В результате строка комментария будет распознаваться как элемент xComment и подсвечивается синим, но слово TODO внутри комментария соответствует группе xTodo и подсвечивается жёлтым (с этой целью мы отдельно настроили подсветку для xTodo).

РЕКУРСИВНЫЕ ВЛОЖЕНИЯ

Язык x определяет блоки в фигурных скобках. Программный блок может также содержать другой программный блок. Это может быть определено такой командой:

:syntax region xBlock start=/{/ end=/}/ contains=xBlock

Например, представьте, что у вас есть такой текст:

while i < b { ~
    if a { ~
        b = c; ~
    } ~
} ~

Первый xBlock начинается с первой { на первой строке. Во второй строке появляется вторая {. Поскольку мы находимся внутри элемента xBlock, и он может содержать другой элемент xBlock, то в этом месте начинается вложенный блок. Строка "b = c" находится внутри второго блока. В следующей строке есть символ }, который соответствует шаблону окончания области xBlock, поэтому в этом месте вложенный блок заканчивается. Поскольку } относится к вложенному блоку, то она не видна первой области xBlock. Наконец, следующая } закрывает первую область xBlock.

ОТДАТЬ КОНЦЫ!

Посмотрите внимательно на следующие два определения:

:syntax region xComment start=/%/ end=/$/ contained
:syntax region xPreProc start=/#/ end=/$/ contains=xComment

Мы определяем, что комментарий может начинаться символом % и продолжается до конца строки. Директива препроцессора начинается с # и продолжается до конца строки. Наше определение директивы препроцессора также включает аргумент "contains=xComment", поскольку на строке с директивой препроцессора может быть указан комментарий. Теперь посмотрим на то, что происходит с текстом:

#define X = Y  % Comment text ~
int foo = 1; ~

Получается, что вторая строка также подсвечивается как xPreProc. Что не так? Ведь директива препроцессора должна заканчиваться с концом строки, как это и указано с помощью "end=/$/".

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

Чтобы избежать этой проблемы, когда включённый синтаксический элемент "съедает" конец строки, используйте аргумент "keepend". Это позволяет справиться с проблемой двойного соответствия концу строки:

:syntax region xComment start=/%/ end=/$/ contained
:syntax region xPreProc start=/#/ end=/$/ contains=xComment keepend
ВЛОЖЕНИЕ МНОГИХ ЭЛЕМЕНТОВ

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

:syntax region xList start=/\[/ end=/\]/ contains=ALL

При помощи этой команды мы разрешили области xList включать любой синтаксический элемент, в том числе и элементы xList, за исключением, конечно, точки начала данного элемента xList, чтобы не создавать бесконечного цикла.

Вы также можете указать группы, которые не могут быть включены в данную группу. Пример:

:syntax region xList start=/\[/ end=/\]/ contains=ALLBUT,xString

позволяет включить все элементы, кроме xString. Значение TOP позволяет включать все элементы, которые не имеют аргумента "contained". Значение CONTAINED, наоборот, используется только для включения элементов, определённых с аргументом "contained". Подробнее см. |:syn-contains|.


44.6 Указание следующих групп для разбора синтаксиса

В нашем языке x также есть выражения вида:

if (condition) then ~

Вам хотелось бы подсвечивать все три элемента различными способами. Однако, "(condition)" и "then" могут также появляться и в других местах, где им будет сопоставлена другая подсветка. Вот как этого добиться:

:syntax match xIf /if/ nextgroup=xIfCondition skipwhite
:syntax match xIfCondition /([^)]*)/ contained nextgroup=xThen skipwhite
:syntax match xThen /then/ contained

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

if not (condition) then ~

Слово "if" принадлежит группе xIf. Поскольку "not" не соответствует указанной следующей группе xIfCondition, то подсвечивается только "if".

Аргумент "skipwhite" указывает Vim, что пробелы и табуляция могут присутствовать между элементами. Похожие аргументы: "skipnl" (позволяет использовать перенос строки между элементами) и "skipempty" (позволяет использовать пустые строки). Обратите внимание, что "skipnl" не пропускает пустую строку, после переноса строки что-то должно быть.


44.7 Другие аргументы

MATCHGROUP

При определении области подсвечивается вся область в соответствии с определённым именем группы. Например, для подсветки текста в круглых скобках по правилам группы xInside, используется команда:

:syntax region xInside start=/(/ end=/)/

Теперь предположим, что нам требуется подсвечивать скобки как-то иначе. Этого можно было бы добиться сложными командами для определения соответствующих областей, но можно поступить намного проще и использовать аргумент "matchgroup". Это позволяет заставить Vim выделять начало и конец области с помощью другой группы подсветки (в данном случае мы используем группу xParen):

:syntax region xInside matchgroup=xParen start=/(/ end=/)/

Аргумент "matchgroup" применяется к шаблонам начала и конца, которые указаны в той же команде. В предыдущем примере как начало, так и конец области подсвечиваются с помощью группы xParen. Чтобы подсвечивать конец области при помощи правил, определённых для группы  xParenEnd используйте такую команду:

:syntax region xInside matchgroup=xParen start=/(/
    \ matchgroup=xParenEnd end=/)/

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

TRANSPARENT

В языке C вам захочется подсвечивать текст в скобках () после слова "while" не так, как текст в скобках после слова "for". В обоих случаях внутри скобок могут быть вложенные области текста в скобках, которые должны подсвечиваться одинаково. Кроме того, необходимо убедиться, что подсветка области в () заканчивается на соответствующей скобке ). Вот как этого всего можно добиться:

:syntax region cWhile matchgroup=cWhile start=/while\s*(/ end=/)/
    \ contains=cCondNest
:syntax region cFor matchgroup=cFor start=/for\s*(/ end=/)/
    \ contains=cCondNest
:syntax region cCondNest start=/(/ end=/)/ contained transparent

Теперь вы можете задать разные правила для подсветки cWhile и cFor. Элемент cCondNest может появляться в каждом из них, но при этом будет подсвечиваться в соответствии с правилами подсветки для включающего его элемента. Добиться этого позволяет аргумент "transparent".

Обратите внимание, что аргумент "matchgroup" указывает на ту же самую группу, что и сам элемент. Зачем тогда пользоваться определением "matchgroup"? Всё дело в том, что побочным эффектом определения "matchgroup" является то, что включённые элементы в этом случае не будут найдены в соответствиях для начала и конца области. Это позволяет избежать ситуации, при которой группа cCondNest соответствует ( сразу после слов "while" или "for". В противном случае, эта группа захватила бы весь текст до соответствующей скобки ) и затем область бы продолжалась. А так cCondNest соответствует только области после соответствия первой скобке (.

СМЕЩЕНИЯ

Предположим, вы хотите определить область текста между скобками () после слова "if", но при этом не хотите включать в область ни "if", ни сами скобки. Этого можно достичь при помощи смещений в шаблонах. Пример:

:syntax region xCond start=/if\s*(/ms=e+1 end=/)/me=s-1

Смещение для шаблона start -- "ms=e+1". "ms" это Match Start, соответствие началу. Так мы определяем смещение для начала соответствия. Заметьте, что это отличается от обычного определения области, когда соответствие начинается в точке начала шаблона. "e+1" позволяет начать область на один символ после окончания соответствия шаблону.

Смещение для шаблона end указано как "me=s-1". "me" это Match End, соответствие концу. "s-1" обозначает начало шаблона соответствия со смещением в один символ, т.е символ, который предшествует шаблону для окончания области. В результате, в тексте:

if (foo == bar) ~

только "foo == bar" будет подсвечиваться по правилам, определённым для группы xCond.

Подробнее о смещения читайте здесь: |:syn-шаблон-смещение|.

ONELINE

Аргумент "oneline" указывает на то, что область ограничена текущей строкой. Например:

:syntax region xIfThen start=/if/ end=/then/ oneline

определяет область, которая начинается со слова "if" и заканчивается словом "then", которые размещаются на одной строке.

Замечание: При использовании аргумента "oneline" область начинается только тогда, когда в той же строке найдено соответствие шаблону end. Без использования аргумента "oneline" Vim вообще не проверяет наличие соответствия шаблону end, а просто начинает область, даже в тех случаях, когда соответствие шаблону end вообще отсутствует в файле.

РАБОТА С ПРОДОЛЖАЮЩИМИСЯ СТРОКАМИ

Теперь наши правила становятся всё сложнее и сложнее. Давайте определим группу для строки препроцессора, которая начинается с символа # в первой колонке и продолжается до конца строки. Строка, которая заканчивается на \ позволяет считать следующую строку продолжением текущей. Чтобы отразить продолжение строки в правилах синтаксиса, введём такие определения:

:syntax region xPreProc start=/^#/ end=/$/ contains=xLineContinue
:syntax match xLineContinue "\\$" contained

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

#define SPAM  spam spam spam \ ~
        bacon and spam ~

В данном случае всё происходит так, как нам требуется. Если же мы хотим иного результата, то можно определить область только в одной строке при помощи аргумента "excludenl" в шаблоне для contained. Например, мы хотим подсветить "end" в группе xPreProc, но только в конце строки. Чтобы область xPreProc не продолжалась на следующей строке, как это делает xLineContinue, мы используем аргумент "excludenl":

:syntax region xPreProc start=/^#/ end=/$/
    \ contains=xLineContinue,xPreProcEnd
:syntax match xPreProcEnd excludenl /end$/ contained
:syntax match xLineContinue "\\$" contained

"excludenl" должно быть помещено перед шаблоном. Поскольку в "xLineContinue" отсутствует аргумент "excludenl", соответствие этой группе позволит продолжить группу xPreProc на следующей строке, как и раннее.


44.8 Кластеры

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

Предположим, в вашем языке имеются синтаксические конструкции для циклов, выражений if, циклов while и функций. Каждая из них содержит одни и те же синтаксические элементы: числа и имена. Вы определяете их таким образом:

:syntax match xFor /^for.*/ contains=xNumber,xIdent
:syntax match xIf /^if.*/ contains=xNumber,xIdent
:syntax match xWhile /^while.*/ contains=xNumber,xIdent

Заметьте, что в каждом определении повторяется один и тот же аргумент "contains=". Если вам потребуется добавить новый синтаксический элемент, то это придётся делать трижды. Синтаксические кластеры упрощают работу с такими определениями, позволяя использовать один кластер для нескольких синтаксических групп.

Чтобы определить кластер для двух элементов, которые включаются в состав указанных групп, используйте такую команду:

:syntax cluster xState contains=xNumber,xIdent

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

:syntax match xFor /^for.*/ contains=@xState:syntax match xIf /^if.*/ contains=@xState
:syntax match xWhile /^while.*/ contains=@xState

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

:syntax cluster xState add=xString

Для удаления синтаксических групп из кластера применяется аргумент remove:

:syntax cluster xState remove=xNumber

44.9 Включение других файлов с правилами синтаксиса

Язык C++ является надмножеством языка C. Поскольку нет смысла дважды описывать одни и те же элементы для языков C и C++, можно подключать файл с правилами синтаксиса языка C в файл с правилами синтаксиса C++. Для этого воспользуемся командой:

:runtime! syntax/c.vim

Команда ":runtime!" ищет все файлы "syntax/c.vim" по путям, указанным в опции 'runtimepath'. Это позволяет использовать определения для правил синтаксиса языка C. Если вы замените файл синтаксиса c.vim или напишите дополнительный файл, то все эти изменения также будут работать в файле синтаксических правил для языка C++.

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

:syntax keyword cppStatement    new delete this friend using

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

Теперь давайте посмотрим на язык Perl. С точки зрения синтаксиса, он состоит из двух различных частей: документации в формате POD и самой программы на языке Perl. Раздел POD начинается с "=head" и заканчивается "=cut".

Было бы разумно определить синтаксис для POD в одном файле и затем использовать эти правила уже в другом файле, где определяется синтаксис для самого языка Perl. Команда ":syntax include" позволяет включать элементы, определённые в другом файле в виде синтаксического кластера. Для Perl мы используем следующие команды:

:syntax include @Pod <sfile>:p:h/pod.vim
:syntax region perlPOD start=/^=head/ end=/^=cut/ contains=@Pod>

Если в файле Perl встречается "=head", то начинается область perlPOD. В этой области содержится кластер @Pod. Таким образом, все элементы, определённые на верхнем уровне правил синтаксиса pod.vim будут работать в этой области. Когда в тесте встречается "=cut", то эта область заканчивается и мы возвращаемся к элементам, определённым в файле Perl.

Команда ":syntax include" достаточно умна, чтобы игнорировать встречающуюся во внешнем файле команду ":syntax clear", а аргументы вроде "contains=ALL" будут включать только элементы, определённые во включённом внешнем файле, но не в файле, который включает этот внешний файл.

"<sfile>:p:h/" использует имя текущего файла (<sfile>), превращая его в полный путь (:p) и затем отделяя от него голову (:h), что приводит к имени каталога, в котором находится файл. В результате подключается файл pod.vim в том же каталоге, что и текущий файл.


44.10 Синхронизация

Легко быть компилятором -- они просматривают текст с начала файла и до конца. Редактору Vim приходится немного труднее. Он начинает прямо с середины файла, где фактически происходит редактирование. Как он справляется с задачей разбора синтаксиса?

Секрет прост: использование команды ":syntax sync". Эта команда позволяет Vim выяснить где он находится. Например, следующая команда заставляет Vim искать в обратном направлении начало или конец комментария в стиле C и начать подсветку синтаксиса с этого места:

:syntax sync ccomment

Вы можете настроить тонкости этого процесса с помощью дополнительных аргументов. Аргумент "minlines" указывает Vim на минимальное количество строк, которое необходимо просматривать, а "maxlines" указывает на максимальное количество строк.

Например, следующая команда заставляет Vim смотреть как минимум за 10 строк до верхней строки экрана:

:syntax sync ccomment minlines=10 maxlines=500

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

Чтобы синхронизация происходила быстрее, вы можете указать Vim какие элементы можно пропустить при анализе. Все соответствия и области, которые используются только при непосредственном отображении на экране можно снабжать аргументом "display".

По умолчанию комментарии подсвечиваются как часть синтаксической группы Comment. Если вы желаете подсвечивать их как-то иначе, то можно определить другую синтаксическую группу:

:syntax sync ccomment xAltComment

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

:syntax sync minlines=150

Большая величина "minlines" приводит к замедлению работы Vim, особенно при прокрутке файла назад.

Наконец, вы можете указать синтаксическую группу, которую следует искать при синхронизации, при помощи команды:

:syntax sync match {имя-группы-синхронизации}
   \ grouphere {имя-группы} {шаблон}

Эта команда указывает Vim, что сразу после {шаблона} начинается синтаксическая группа {имя-группы}. Для определения имени группы синхронизации используется {имя-группы-синхронизации}. Например, в языке сценариев sh выражение if начинается со слова "if" и заканчивается словом "fi":

if [ --f file.txt ] ; then ~
    echo "File exists" ~
fi ~

Чтобы определить директиву "grouphere" для этого синтаксиса, используйте следующую команду:

:syntax sync match shIfSync grouphere shIf "\<if\>"

Аргумент "groupthere" указывает Vim на шаблон, которым заканчивается группа. Например, конец группы if/fi определяется так:

:syntax sync match shIfSync groupthere NONE "\<fi\>"

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

Вы также можете определять соответствия и области без аргументов "grouphere" и "groupthere". Такие группы пропускаются во время синхронизации. Например, следующая команда пропускает области внутри {}, даже если они соответствуют другим командам синхронизации:

:syntax sync match xSpecial /{.*}/

Подробнее о синхронизации читайте в справочнике: |:syn-sync|.


44.11 Установка файла синтаксиса в системе

Когда ваш файл синтаксиса готов к использованию, поместите его в каталог "syntax" в одном из путей, указанных в 'runtimepath'. На Unix это может быть, например, каталог "~/.vim/syntax".

Имя файла с правилами синтаксиса должно соответствовать типу файла с добавлением расширения ".vim". Для нашего языка x полное имя файла будет:

~/.vim/syntax/x.vim ~

Кроме того, вам нужно позаботиться о том, чтобы тип файла правильно распознавался Vim. См. |43.2|.

Если ваш файл синтаксиса отлично работает, то вы можете поделиться им с другими пользователями Vim. Прежде всего прочитайте следующий раздел, чтобы убедиться, что файл будет также хорошо работать и у других пользователей. Затем отправьте его по почте координатору проекта Vim: <Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.>;. Также поясните, как должен определяться тип файла. Если всё будет работать так, как полагается, то ваш файл может быть включён в состав поставки следующей версии Vim!

ДОБАВЛЕНИЯ К СУЩЕСТВУЮЩЕМУ ФАЙЛУ СИНТАКСИСА

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

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

:syntax keyword cType off_t uint

Запишите файл с тем же именем, что и оригинальный файл синтаксиса. В данном случае это будет "c.vim". Теперь поместите его в каталог, который находится ближе к концу списка каталогов в 'runtimepath'. Это позволяет загружать ваш файл после стандартного файла синтаксиса. На Unix это может быть, например,

~/.vim/after/syntax/c.vim ~

44.12 Переносимый формат файла синтаксиса

Было бы здорово, если пользователи Vim могли бы обмениваться файлами синтаксиса. Для этого требуется выполнение ряда рекомендаций при создании файла синтаксических правил.

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

" Файл синтаксиса Vim
" Язык:            C
" Автор:        Bram Moolenaar <Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.>;
" Последнее изменение:    2001 Jun 18
" Замечание:        Подключается в файле синтаксиса C++.

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

Выберите хорошее имя для вашего файла синтаксиса. Используйте строчные буквы и цифра в имени. Не стоит делать имя слишком длинным: оно будет использоваться во многих местах: имя файла синтаксиса "name.vim", 'filetype', b:current_syntax, начало каждой синтаксической группы (nameType, nameStatement, nameString) и т.д.

Начните с проверки переменной "b:current_syntax". Если она существует, то это значит, что был загружен другой файл синтаксиса, из каталога, указанного в 'runtimepath' где-то раннее. Чтобы поддерживать Vim 5.8, используйте следующий код:

if version < 600
  syntax clear
elseif exists("b:current_syntax")
  finish
endif

Установите "b:current_syntax" в значение имени синтаксиса в конце. Не забудьте, что это будет также проделано включёнными файлами, так что если вы включаете два файла, то вам придётся сбросить переменную "b:current_syntax".

Если вы желаете, чтобы ваш файл синтаксиса работал с Vim 5.x, то добавьте проверку переменной v:version. В качестве примера смотрите yacc.vim.

Не включайте в файл ничего, что является пользовательской настройкой. Не устанавливайте значения опций 'tabstop', 'expandtab' и т.д. Всё это имеет отношение к модулям типа файлов, а не к синтаксису.

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

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

if version >= 508 || !exists("did_c_syn_inits")
  if version < 508
    let did_c_syn_inits = 1
    command -nargs=+ HiLink hi link <args>
  else
    command -nargs=+ HiLink hi def link <args>
  endif

  HiLink nameString    String
  HiLink nameNumber    Number
  ... etc ...

  delcommand HiLink
endif

Для элементов, которые не используются при синхронизации, добавьте аргумент "display", чтобы ускорить прокрутку назад и обновление экрана с помощью CTRL-L.


Следующая глава: Выбор языка
Авторские права: см. Авторские права