Возвышенный текст, как сделать подсветку синтаксиса
Обновлено: 21.11.2024
Если вы пишете шейдеры, то наверняка сталкивались с проблемой, в чем их писать. Поскольку настоящей IDE для шейдеров не существует (а серьезно, почему ее нет? На данный момент они достаточно распространены, чтобы я больше не могу представить, что это нишевый рынок, что, как я полагаю, является причиной его игнорирования.), вы найдете текстовый редактор, который достаточно легкий и настраиваемый, чтобы помочь вам выполнить работу как можно лучше, и вы просто имеете дело с Это. И во многих случаях кто-то в конце концов пишет базовую подсветку синтаксиса для выбранного вами редактора, и большинство из нас счастливы просто получить все, что мы примем и продолжим. Я испытал это с NShader в Visual Studio, с файлом MJP для NotePad++ и с тем, с чего я начал для Sublime Text 3 (извините, кто бы это ни писал, я, честно говоря, не помню, откуда он взялся на данный момент).
За год или около того, что я использую ST3, я обнаружил, что его достаточно легко настраивать и расширять, поэтому у меня появилась высокая мотивация делать это. Частью этой работы было создание моего собственного файла синтаксиса для HLSL. Итак, мой файл синтаксиса не слишком сложен и даже не настолько полон, как мне бы хотелось, но… регулярное выражение (Примечание: если кто-то гораздо лучше меня разбирается в регулярных выражениях, смотрит на это и смеется над моей жалкостью, я полностью приветствую помощь вносим улучшения!). Тем не менее, я определил определения функций и вызовы, и это открывает интересную возможность в ST3, помимо простой подсветки синтаксиса; с этой информацией, если вы поместите файлы шейдера в файл возвышенного проекта, вы автоматически подключитесь к инфраструктуре ST3 Goto Definition. Вот как это выглядит:
И после того, как вы это заработаете, будет совсем немного, чтобы заставить работать автозаполнение для всей библиотеки. К сожалению, я не могу поделиться своим решением для индексации автозаполнения, но могу поделиться своим файлом синтаксиса. Вот! Надеюсь, вам понравится, и снова я полностью приветствую предложения по улучшению. Кроме того, вот мой файл темы, если вас интересует очень специфичное для HLSL цветовое кодирование, но это абсолютно не обязательно.
В прошлом году я начал экспериментировать с языком программирования Faust и хотел улучшить подсветку синтаксиса для него в Sublime Text, текстовом редакторе, который я использую для программирования. Я не хотел писать файл определения возвышенного синтаксиса вручную, так как это довольно сложно, поэтому вместо этого я написал программу для автоматического создания файла из формальной грамматики языка. Это тоже оказалось сложно! Но это мне больше по вкусу.
Примечание: вы можете просмотреть исходный код и документацию на Github и установить программу с помощью pip install sublime-from-cfg (требуется Python 3.9). Например, что-то вроде:
Сгенерированный мной синтаксис Faust находится здесь.
Файлы .sublime-syntax Sublime Text •
Подсветка синтаксиса уже включена в Sublime Text для многих популярных языков, таких как (например) C, где код автоматически окрашивается примерно так:
Обратите внимание, что if , printf и "Hello World!" окрашиваются по-разному. Чтобы создать эту подсветку синтаксиса, минимальный файл .sublime-syntax будет выглядеть примерно так:
Механизм подсветки синтаксиса имеет стек контекста, который всегда запускается в основном контексте в начале редактируемого файла. Всякий раз, когда один из объектов сопоставления в контексте соответствует (как регулярное выражение) текущему тексту, контекст может быть помещен в стек или может быть извлечено некоторое количество контекстов, и механизм синтаксиса переходит к следующей части редактируемого текста. файл. Например, когда появляется двойная кавычка, строковый контекст помещается в стек. Затем механизм синтаксиса продвигается вперед, пока не появится следующая двойная кавычка, а затем строковый контекст извлекается из стека, и механизм синтаксиса возвращается к основному контексту.
Это лишь самые основные функции, доступные авторам файлов .sublime-syntax. Вы также можете выполнять такие действия, как встраивание одного языка в другой (например, чтобы выделить HTML-тег как JavaScript), выполнять «недетерминированный» синтаксический анализ, прерывая его, когда происходит что-то неожиданное, и пробуя другую стратегию синтаксического анализа, и многое другое.
Языки программирования могут быть довольно сложными, поэтому файлы .sublime-syntax также становятся довольно сложными. Официальный файл определения синтаксиса языка Sublime Text C (на момент написания) состоит из 1320 строк. Длина JavaScript составляет 2533 строки. Длина Java составляет 3234 строки.
У Фауста уже есть определение языка •
Исходный код языка программирования Faust находится в свободном доступе на Github. Парсер для Faust генерируется через исходный файл yacc.Yacc — это генератор синтаксических анализаторов: программа, которая использует формальную грамматику для языка программирования и генерирует синтаксический анализатор (компонент компилятора) для этого языка. Это компилятор для компиляторов. Мне важно следующее: это означает, что уже есть краткое высокоуровневое описание языка программирования Faust. Выдержка из ссылки выше:
Это определяет допустимую программу Faust. Слово в нижнем регистре является нетерминалом. Слово в верхнем регистре является терминалом. Нетерминалы можно расширить, выбрав один из вариантов справа; терминалы («терминал» в смысле «конечный») больше не могут быть расширены.
Чтобы интерпретировать вышеизложенное: программа Faust начинается с программы . Это расширяется до stmtlist (единственный вариант). stmtlist может быть расширен либо до первого параметра (пустая строка), либо до второго параметра (stmtlist variantlist statment). Первый термин снова stmtlist. Это рекурсивное определение stmtlist, что означает, что stmtlist может ссылаться на оператор variantlist, повторяющийся любое количество раз. Пропустив список вариантов (который я пропустил, потому что он не очень информативен), оператор, по-видимому, может быть расширен несколькими различными способами – через некоторые догадки о том, что означают различные имена, оператор может быть либо импортом, либо объявлением (в двух различными способами), определение или «документ» (в данном случае это документация).
Если вы подробнее прочитаете приведенный выше связанный файл, то увидите, что все остальные нетерминалы (имя, строка, определение и т. д.) отображаются слева со своими вариантами расширения.
Бесконтекстные грамматики и генераторы синтаксических анализаторов •
Языковые описания этой формы, в которых нетерминалы раскрываются как строки нетерминалов и терминалов, известны как контекстно-свободные грамматики. Многие (даже большинство?) языков программирования можно описать с помощью контекстно-свободной грамматики. Контекстно-свободные грамматики также изучаются в теории формального языка, в теоретической лингвистике и информатике.
Контекстно-свободные грамматики также очень удобны для людей, создающих свои собственные языки программирования, поскольку генераторы синтаксических анализаторов, такие как yacc, могут использоваться для создания синтаксических анализаторов для них — генератор синтаксических анализаторов использует контекстно-свободную грамматику и создает синтаксический анализатор для языка.< /p>
Это означает, что многие языки программирования уже имеют контекстно-свободную грамматику, описывающую их либо как часть исходного кода языка, либо как часть его спецификации.
Преобразование CFG в возвышенное определение синтаксиса •
Итак, как преобразовать контекстно-свободную грамматику в файл .sublime-syntax? Я проиллюстрирую этот процесс несколькими постепенно усложняющимися примерами. (Хотя я опущу некоторые усложняющие детали.)
1. Только одно производство на нетерминал •
Во-первых, предположим, что у меня есть простая контекстно-свободная грамматика, в которой каждый нетерминал имеет только одну продукцию:
Здесь main , a и b — нетерминалы, а 'c', 'd', 'e' и 'f' — терминалы. Это очень скучный язык, единственной допустимой строкой которого является cdef. Это потому, что main расширяется до строки нетерминалов a, за которой следует b, каждый из a и b расширяется до пары терминалов, а затем расширение останавливается. На любом этапе нет альтернативного производства, которое можно было бы выбрать.
Чтобы отобразить это как определение .sublime-syntax, я создаю контекст для каждого нетерминала и каждого терминала:
Совпадение: инструкция '' означает "всегда совпадать"; set означает «извлечь текущий контекст, а затем отправить следующие контексты». Поэтому, когда запускается основной контекст, он сразу же появляется и заменяется контекстами b и a. Это в порядке, обратном производственному main : a b , так что a будет наверху стека. Затем аналогичным образом контекст a немедленно извлекается и заменяется терминалом-d и терминалом-c, соответствующими произведению a: 'c' 'd' . Контекст терминала-c будет совпадать с литеральным символом c, а затем всплывать (что делает терминал-d вершиной стека), а любой другой символ, не являющийся пробелом, будет помечен как недопустимый (это то, что делает включенный контекст ошибки — \S является регулярным выражением для «любого символа, отличного от пробела»). После сопоставления c, а затем d для контекста терминала-d, b оказывается на вершине стека и заменяется на [terminal-f, terminal-e] , так что e и f сопоставляются по очереди.
2. Несколько постановок с разными начальными наборами •
Несколько более сложный пример, когда нетерминал может расширяться до разных продуктов:
Теперь нетерминал a может соответствовать либо 'c', за которым следует 'd' или терминалу 'x' . Это более интересный язык, который может сопоставлять две строки: cdef и xef. (Хорошо, это только немного интереснее.)
Основной контекст по-прежнему выглядит так же, как и b , потому что оба этих нетерминала имеют только одно производство, но мне нужно изменить контекст a.Я могу сделать это с помощью упреждающего регулярного выражения, которое будет сопоставлять, но не использовать текст, так что его можно будет сопоставить позже:
Вместо безусловной замены текущего контекста на [terminal-d, terminal-c] , я устанавливаю контексты, соответствующие следующему символу. Если следующим символом является c, то регулярное выражение (?=c) соответствует, и контекст заменяется на [terminal-d, terminal-c] . Если вместо этого следующим символом является x, то регулярное выражение (?=x) совпадает, и контекст заменяется на terminal-x . Если следующий символ не является ни c, ни x, то это недопустимая строка в моем простом языке: контекст ошибки совпадет и пометит символ как недействительный.
В этом случае производство для обоих начинается с терминалов, поэтому легко понять, каким должно быть регулярное выражение с опережением, но производство также может начинаться с нетерминалов. Если, например, в языке есть правило main : a b | 'з'; , тогда мне нужно было бы знать, что выбрать b или 'z' . В этом случае я бы рекурсивно вычислил (для каждого нетерминала) набор возможных терминалов, с которых он мог начаться. Нетерминал a может начинаться с 'c' или 'x' , поэтому упреждающее регулярное выражение, соответствующее любому из этих символов, должно привести к выбору первой продукции a b . «z» должен привести к выбору второй продукции «z». (Я пропускаю некоторые детали, которые применимы, когда продукция может соответствовать пустой строке — см. страницу википедии по синтаксическим анализаторам LL для получения дополнительной информации.)
3. Несколько производств с перекрывающимся начальным набором •
Самая интересная и сложная ситуация, когда несколько продуктов могут начинаться с одного и того же терминала, и поэтому я не могу использовать регулярное выражение с опережением, чтобы решить, какой из них выбрать.
Это по-прежнему очень простой язык, в котором допустимы только три строки: cdef , czef и xef . Теперь контекст для a должен измениться, чтобы приспособиться к новой продукции 'c' 'z' , но, к сожалению, две продукции теперь начинаются с 'c', и регулярное выражение с опережением (?=c) не различает их.
Прежде чем я объясню, как я справляюсь с этим, я действительно хочу немного изменить свой подход к предыдущей ситуации и изменить способ обработки неожиданных символов:
Весь смысл этого заключается в обеспечении недетерминированного синтаксического анализа.
Синтаксический движок Sublime Text допускает недетерминированный синтаксический анализ. Вместо отправки или установки контекста вы можете ветвиться: при переходе вы предоставляете список контекстов, которые нужно попробовать, один за другим. Если во время одного из этих контекстов происходит действие fail, синтаксический движок возвращается к тому состоянию, в котором он был при ветвлении, и повторяет попытку со следующим контекстом. Ниже приведены полные контексты, соответствующие этому примеру, которые отличаются от предыдущей версии:
Всякий раз, когда предварительный просмотр может соответствовать более чем одной продукции, я создаю специальный контекст ветви (здесь a@01 ), чтобы попробовать каждую продукцию последовательно. Контекст для каждой продукции подталкивает пару контекстов для обработки успеха и неудачи соответственно, а затем контексты, соответствующие символам для этой продукции. Контекст успеха — это pop3, который просто выскакивает из контекста ветки (и пропускает буфер pop2), а контекст неудачи запускает специальное действие «попробовать следующую ветку». Последняя попытка для каждой ветки не имеет этого специального триггера (поскольку нет другой продукции, которую можно было бы попробовать), поэтому она просто выскакивает на pop2, чтобы можно было инициировать следующий сбой вверх по стеку.
Подробнее •
Вот и все! Я упустил некоторые детали, чтобы сделать историю относительно простой, но есть еще несколько приемов, которые я использую в неоднозначных ситуациях. Есть некоторые грамматики, с которыми я не могу справиться — например, леворекурсивные грамматики — и вы можете прочитать еще несколько подробностей о моем подходе на странице Github для проекта. Общий подход к синтаксическому анализу принадлежит Адриану Джонстону и Элизабет Скотт, хотя адаптация этого подхода к созданию файла .sublime-syntax — это моя собственная работа. Формат файла, который я использую для представления контекстно-свободных грамматик, взят из sbnf Бенджамина Шаафа, который очень похож на мой проект (хотя реализован совершенно по-другому).
Я хочу изменить/добавить подсветку синтаксиса для языка в Sublime 2/3.
Например, я хочу, чтобы ключевое слово было окрашено в этот цвет в JavaScript.
Как я могу это сделать?
Я знаю, что файл настроек JavaScript находится в C:\Program Files\Sublime Text 3\Packages , но я не знаю, что изменить или мне нужно создать новый файл настроек JavaScript где-то в этой папке % APPDATA%\Sublime Text 3 .
5 ответов 5
Подсветка синтаксиса управляется используемой вами темой, доступ к которой можно получить через «Настройки» -> «Цветовая схема». Темы выделяют различные ключевые слова, функции, переменные и т. д. с помощью областей видимости, которые определяются серией регулярных выражений, содержащихся в файле .tmLanguage в каталоге/пакете языка. Например, JavaScript.tmLanguage присваивает области source.js и variable.language.js ключевому слову this. Поскольку Sublime Text 3 использует формат ZIP-файла .sublime-package для хранения всех настроек по умолчанию, редактировать отдельные файлы не очень просто.
К сожалению, не все темы содержат все области действия, поэтому вам придется поэкспериментировать с разными, чтобы найти ту, которая хорошо выглядит и обеспечивает нужное выделение. В Sublime Text включен ряд тем, и многие другие доступны через Package Control, который я настоятельно рекомендую установить, если вы еще этого не сделали. Убедитесь, что вы следуете указаниям ST3.
Случилось так, что я разработал неоновую цветовую схему, доступную через Управление пакетами, на которую вы, возможно, захотите взглянуть. Моей главной целью, помимо того, что я пытался сделать так, чтобы широкий спектр языков выглядел как можно лучше, было определить как можно больше разных областей применения — гораздо больше, чем включено в стандартные темы. Хотя определение языка JavaScript не такое подробное, как, например, в Python, Neon по-прежнему предлагает гораздо больше разнообразия, чем некоторые стандартные языки, такие как Monokai или Solarized .
Я должен отметить, что для этого изображения я использовал определение языка Better JavaScript от @int3h вместо того, которое поставляется с Sublime. Его можно установить с помощью Package Control.
ОБНОВЛЕНИЕ
Недавно я обнаружил другое определение языка замены JavaScript — JavaScriptNext — ES6 Syntax. Он имеет больше возможностей, чем базовый JavaScript или даже лучший JavaScript. В том же коде это выглядит так:
Кроме того, поскольку я изначально написал этот ответ, @skuroda выпустил PackageResourceViewer через Управление пакетами. Это позволяет вам легко просматривать, редактировать и/или извлекать части или целые пакеты .sublime-package. Таким образом, при желании вы можете напрямую редактировать цветовые схемы, включенные в Sublime.
ЕЩЕ ОБНОВЛЕНИЕ
С выпуском почти всех пакетов по умолчанию на Github изменения происходят быстро и яростно. Старый синтаксис JS был полностью переписан, чтобы включить лучшие части синтаксиса JavaScript Next ES6, и теперь он полностью совместим с ES6, насколько это возможно. Было внесено тонна других изменений, чтобы охватить угловые и граничные случаи, улучшить согласованность и просто сделать его лучше в целом. Новый синтаксис был включен в последнюю (на данный момент) сборку для разработчиков 3111.
Если вы хотите использовать какой-либо из новых синтаксисов с текущей бета-сборкой 3103, просто клонируйте репозиторий Github куда-нибудь и свяжите JavaScript (или любой другой язык (языки)) с вашим каталогом Packages. Найдите его на вашу систему, выбрав Preferences -> Browse Packages. . Затем просто выполняйте git pull в исходном каталоге репо время от времени, чтобы обновлять любые изменения, и вы сможете наслаждаться последними и лучшими! Я должен отметить, что репозиторий использует новый формат .sublime-syntax вместо старого .tmLanguage, поэтому они не будут работать со сборками ST3 до 3084 или со ST2 (в обоих случаях вы должны были обновиться до последней бета-версии). или в любом случае сборка для разработчиков).
В настоящее время я настраиваю свою цветовую схему Neon, чтобы она могла работать со всеми новыми областями действия в новом синтаксисе JS, но большинство из них должно быть уже реализовано.
Разработка Sublime Text перешла к версии 3.
В результате эта ветка для Sublime Text 2 больше не будет обновляться. Выберите последнюю ветку на панели внизу слева и рассмотрите возможность обновления Sublime Text.
Определения синтаксиса делают Sublime Text осведомленным о языках программирования и разметки. Наиболее заметно, что они работают вместе с цветами, чтобы обеспечить подсветку синтаксиса. Определения синтаксиса определяют области, которые делят текст в буфере на именованные области. Несколько функций редактирования в Sublime Text широко используют эту подробную контекстную информацию.
По сути, определения синтаксиса состоят из регулярных выражений, используемых для поиска текста, а также более или менее произвольных строк, разделенных точками, называемых областями или именами областей. Для каждого вхождения заданного регулярного выражения Sublime Text присваивает соответствующему тексту соответствующее имя области действия.
Предпосылки¶
Чтобы следовать этому руководству, вам необходимо установить AAAPackageDev, пакет, предназначенный для упрощения создания новых определений синтаксиса для Sublime Text. Следуйте указаниям по установке в разделе «Приступая к работе» файла readme.
Формат файла¶
Sublime Text использует файлы списка свойств (Plist) для хранения определений синтаксиса. Однако, поскольку редактирование файлов XML является трудоемкой задачей, вместо этого мы будем использовать YAML, а затем преобразовать его в формат Plist. Здесь на помощь приходит пакет AAAPackageDev (упомянутый выше).
Если во время работы с этим руководством вы столкнулись с непредвиденными ошибками, скорее всего, виноваты AAAPackageDev или YAML. Не думайте сразу, что проблема связана с ошибкой в Sublime Text.
В любом случае редактируйте файлы Plist вручную, если предпочитаете работать с XML, но всегда помните об их различных потребностях в отношении escape-последовательностей, многих XML-тегов и т. д.
Области действия¶
Области действия — это ключевое понятие в Sublime Text. По сути, это именованные текстовые области в буфере. Они ничего не делают сами по себе, но Sublime Text заглядывает к ним, когда ему нужна контекстная информация.
Например, когда вы запускаете фрагмент, Sublime Text проверяет область действия, связанную с фрагментом, и смотрит на положение курсора в файле. Если текущая позиция курсора соответствует селектору области действия фрагмента, Sublime Text отключает его. В противном случае ничего не происходит.
Области действия и селекторы областей действия
Существует небольшая разница между областями и селекторами областей: области действия — это имена, определенные в определении синтаксиса, а селекторы областей используются в таких элементах, как фрагменты и привязки клавиш для целевые масштабы. При создании нового определения синтаксиса вы заботитесь об областях; когда вы хотите ограничить фрагмент определенной областью, вы используете селектор области.
Области могут быть вложены друг в друга, чтобы обеспечить высокую степень детализации. Вы можете детализировать иерархию так же, как с помощью селекторов CSS. Например, благодаря селекторам областей вы можете активировать привязку клавиш только в строках с одинарными кавычками в исходном коде Python, но не внутри строк с одинарными кавычками на любом другом языке.
Sublime Text унаследовал идею областей действия от Textmate, текстового редактора для Mac. Онлайн-руководство Textmate содержит дополнительную информацию о селекторах областей, которые также полезны для пользователей Sublime Text. В частности, цветовые схемы делают чрезмерное использование областей видимости для стилизации каждого аспекта языка в желаемом цвете.
Как работают определения синтаксиса¶
По своей сути определения синтаксиса представляют собой массивы регулярных выражений в сочетании с именами областей действия. Sublime Text попытается сопоставить эти шаблоны с текстом буфера и прикрепить соответствующее имя области ко всем вхождениям. Эти пары имен регулярных выражений и областей называются правилами.
Правила применяются по порядку, по одной строке за раз. Правила применяются в следующем порядке:
- Правило, которое соответствует первой позиции в строке.
- Правило, которое идет первым в массиве
Каждое правило использует совпадающую текстовую область, которая поэтому будет исключена из попытки сопоставления следующего правила (за исключением нескольких исключений). На практике это означает, что при создании нового определения синтаксиса следует позаботиться о переходе от более конкретных правил к более общим. В противном случае жадное регулярное выражение может проглотить части, которые вы хотели бы оформить по-другому.
Определения синтаксиса из отдельных файлов можно комбинировать, а также применять рекурсивно.
Ваше первое определение синтаксиса¶
В качестве примера давайте создадим определение синтаксиса для фрагментов Sublime Text. Мы будем стилизовать содержимое фрагмента, а не весь файл .sublime-snippet.
Поскольку определения синтаксиса в основном используются для подсветки синтаксиса, мы будем использовать фразу для стиля, чтобы обозначить разбить файл исходного кода на области действия. Однако имейте в виду, что цвета — это не определение синтаксиса, а области действия имеют гораздо больше применений, чем подсветка синтаксиса.
Вот элементы, которые мы хотим стилизовать во фрагменте:
- Переменные ( $PARAM1 , $USER_NAME . )
- Простые поля ($0, $1.)
- Сложные поля с заполнителями ( $ )
- Вложенные поля ( $!> )
- Управляющие последовательности ( \\$ , \\ . )
- Недопустимые последовательности ( $ , . )
Вот элементы, которые мы не хотим стилизовать, потому что они слишком сложны для этого примера:
Прежде чем продолжить, убедитесь, что вы установили пакет AAAPackageDev, как описано выше.
Создание нового определения синтаксиса¶
Чтобы создать новое определение синтаксиса, выполните следующие действия:
- Перейти к Инструменты | Пакеты | Разработка пакета | Новое определение синтаксиса
- Сохраните новый файл в папке Packages/User как файл .YAML-tmLanguage.
Теперь вы должны увидеть такой файл:
Давайте рассмотрим ключевые элементы.
имя Имя, которое Sublime Text будет отображать в раскрывающемся списке определения синтаксиса. Используйте короткое описательное имя. Как правило, вы будете использовать имя языка программирования, для которого вы создаете определение синтаксиса. scopeName Область верхнего уровня для этого определения синтаксиса. Он принимает форму источника. или текст. . Для языков программирования используйте исходный код. Для разметки и всего остального используйте текст. Типы файлов Это список расширений файлов (без точки в начале).При открытии файлов этих типов Sublime Text автоматически активирует для них это определение синтаксиса. uuid Это уникальный идентификатор для данного определения синтаксиса. Каждое новое определение синтаксиса получает свой собственный uuid. Даже если сам Sublime Text игнорирует это, не изменяйте это. Patterns Контейнер для ваших шаблонов.
Для нашего примера заполните шаблон следующей информацией:
YAML не является очень строгим форматом, но может вызвать головную боль, если вы не знаете его соглашений. Он поддерживает одинарные и двойные кавычки, но вы также можете опустить их, если содержимое не создает другой литерал YAML. Если преобразование в Plist не удалось, взгляните на панель вывода для получения дополнительной информации об ошибке. Позже мы объясним, как преобразовать определение синтаксиса в YAML в Plist. Это также затронет первую закомментированную строку в шаблоне.
--- и . являются необязательными.
Анализ шаблонов¶
Массив шаблонов может содержать несколько типов элементов. Мы рассмотрим некоторые из них в следующих разделах. Если вы хотите узнать больше о шаблонах, обратитесь к онлайн-руководству Textmate.
Совпадения¶
Совпадения имеют следующую форму:
Синтаксис регулярных выражений в определениях синтаксиса
Sublime Text использует синтаксис Oniguruma для регулярных выражений в определениях синтаксиса. Несколько существующих определений синтаксиса используют функции, поддерживаемые этим движком регулярных выражений, которые не являются частью регулярных выражений в стиле Perl, отсюда и требование для Oniguruma.
match Регулярное выражение, которое Sublime Text будет использовать для поиска совпадений. name Имя области, которая должна применяться к любым вхождениям match . comment Необязательный комментарий к этому шаблону.
Вернемся к нашему примеру. Это выглядит так:
То есть убедитесь, что массив шаблонов пуст.
Теперь мы можем начать добавлять наши правила для фрагментов Sublime. Начнем с простых полей. Их можно сопоставить с регулярным выражением следующим образом:
Затем мы можем построить наш шаблон следующим образом:
Выбор правильного имени области
Иногда названия областей действия неочевидны. Ознакомьтесь с соглашениями об именовании Textmate, чтобы получить рекомендации по именам областей действия. AAAPackageDev автоматически предоставляет дополнения для имен областей в соответствии с этими соглашениями. Важно повторно использовать изложенные здесь основные категории, если вы хотите добиться максимальной совместимости с существующими цветами.
Цветовые схемы имеют жестко заданные имена областей действия. Они не могут включать в себя все имена областей, о которых вы только можете подумать, поэтому они нацелены на стандартные, а иногда и на некоторые более редкие (например, для CSS или Markdown). Это означает, что две цветовые схемы, использующие одно и то же определение синтаксиса, могут отображать текст по-разному!
Имейте в виду, что вы должны использовать имя области действия, которое лучше всего соответствует вашим потребностям или предпочтениям. Было бы совершенно нормально назначать область видимости, такую как Constant.numeric, чему-либо, кроме числа, если у вас есть веская причина для этого.
И мы также можем добавить его в наше определение синтаксиса:
Вы должны использовать два пробела для отступа. Это рекомендуемый отступ для YAML, который соответствует спискам, как показано выше.
Теперь мы готовы преобразовать наш файл в .tmLanguage. В определениях синтаксиса используется расширение Textmate .tmLanguage из соображений совместимости. Как объяснялось выше, это просто XML-файлы Plist.
Выполните следующие действия, чтобы выполнить преобразование:
- Убедитесь, что в меню Инструменты | Создайте систему или выберите Преобразовать в .
- Нажмите F7
- Файл .tmLanguage будет создан в той же папке, что и ваш файл .YAML-tmLanguage
- Sublime Text перезагрузит изменения в определении синтаксиса.
Если вам интересно, почему AAAPackageDev знает, во что вы хотите преобразовать файл: это указано в первой строке комментария.
Теперь вы создали свое первое определение синтаксиса. Затем откройте новый файл и сохраните его с расширением .ssraw. Имя синтаксиса буфера должно автоматически переключиться на «Sublime Snippet (Raw)», и вы должны получить подсветку синтаксиса, если введете $1 или любое другое простое поле фрагмента.
Перейдем к созданию еще одного правила для переменных среды.
Повторите описанные выше шаги, чтобы обновить файл .tmLanguage.
Точная настройка совпадений¶
Например, вы могли заметить, что весь текст в $PARAM1 оформлен одинаково. В зависимости от ваших потребностей или ваших личных предпочтений, вы можете выделить $. Здесь на помощь приходят захваты. Используя захваты, вы можете разбить шаблон на компоненты, чтобы нацеливаться на них по отдельности.
Давайте перепишем один из наших предыдущих шаблонов, чтобы использовать захваты:
Захваты усложняют ваше правило, но они довольно просты. Обратите внимание, как числа относятся к группам в скобках слева направо. Конечно, вы можете иметь столько групп захвата, сколько захотите.
Написание 1 на новой строке и нажатие клавиши Tab приведет к автозаполнению до '1': благодаря AAAPackageDev.
Возможно, вы хотели бы, чтобы другая область визуально соответствовала этой. Идите и измените его тоже.
Как и в случае с обычными регулярными выражениями и заменами, группа захвата '0' применяется ко всему совпадению.
Правила начала-конца¶
До сих пор мы использовали простое правило. Хотя мы уже видели, как разбивать шаблоны на более мелкие компоненты, иногда вам может понадобиться нацелиться на большую часть исходного кода, которая четко ограничена начальными и конечными метками.
Литеральные строки, заключенные в кавычки или другие конструкции-разделители, лучше обрабатываются правилами начала-конца. Это скелет одного из этих правил:
Ну, по крайней мере, в самой простой их версии. Давайте взглянем на тот, который включает в себя все доступные параметры:
Некоторые элементы могут показаться знакомыми, но их сочетание может пугать. Давайте рассмотрим их по отдельности.
имя Как и в случае с простым захватом, это устанавливает следующее имя области для всего совпадения, включая начальные и конечные метки. По сути, это создаст вложенные области видимости для beginCaptures, endCaptures и шаблонов, определенных в этом правиле. Необязательный. contentName В отличие от имени, это применяет только имя области к заключенному тексту. Необязательный. начните регулярное выражение для открывающей метки для этой области. end Регулярное выражение для конечной метки для этой области. beginCaptures Захватывает маркер начала. Они работают как захваты для простых совпадений. Необязательный. endCaptures То же, что и beginCaptures, но для конечного маркера. Необязательный. Patterns Массив шаблонов для сопоставления только с содержимым начала-конца; они не сопоставляются с текстом, используемым begin или end сами по себе. Необязательно.
Мы будем использовать это правило для оформления вложенных сложных полей в сниппетах:
Это самый сложный шаблон, который мы увидим в этом руководстве. Ключи начала и конца говорят сами за себя: они определяют область, заключенную между $ < : и >. Нам нужно заключить шаблон начала в кавычки, потому что в противном случае завершающий : укажет синтаксическому анализатору ожидать другой ключ словаря. beginCaptures далее делит метку начала на более мелкие области.
Однако самое интересное — это шаблоны. Рекурсия и важность упорядочения наконец-то проявились здесь.
Выше мы видели, что поля могут быть вложенными. Чтобы учесть это, нам нужно рекурсивно стилизовать вложенные поля. Вот что делает правило включения, когда мы присваиваем ему значение $self: оно рекурсивно применяет все наше определение синтаксиса к тексту, захваченному нашим правилом begin-end. Эта часть исключает текст, используемый регулярными выражениями для begin и end по отдельности.
Помните, совпадающий текст используется; таким образом, он исключается из следующей попытки сопоставления и не может сопоставляться снова.
Чтобы закончить сложные поля, мы будем оформлять заполнители в виде строк. Поскольку мы уже сопоставили все возможные токены внутри сложного поля, мы можем с уверенностью сказать Sublime Text, чтобы любой оставшийся текст ( . ) имел буквальную строковую область. Обратите внимание, что это не работает, если мы сделали шаблон жадным ( .+ ), потому что он включает возможные вложенные ссылки.
Мы могли бы использовать contentName: string.other.ssraw вместо последнего шаблона, но таким образом мы показываем важность упорядочения и того, как используются совпадения.
Последние штрихи¶
Наконец, давайте стилизуем escape-последовательности и недопустимые последовательности, а затем мы можем подвести итоги.
Единственная сложность здесь — не забывать, что [] заключает массивы в YAML и, следовательно, должен быть заключен в кавычки. В остальном правила довольно просты, если вы знакомы с регулярными выражениями.
Однако вы должны позаботиться о том, чтобы поместить второе правило после всех других, соответствующих символу $, поскольку в противном случае оно будет использовано и приведет к тому, что каждое последующее выражение не будет соответствовать.
Кроме того, даже после добавления этих двух дополнительных правил обратите внимание, что наше рекурсивное правило начала-конца, описанное выше, продолжает работать должным образом.
Наконец, вот окончательное определение синтаксиса:
Существует больше доступных конструкций и методов повторного использования кода с использованием «репозитория», но приведенные выше объяснения должны помочь вам приступить к созданию определений синтаксиса.
Если вы ранее использовали JSON для определения синтаксиса, вы по-прежнему можете это сделать, поскольку AAAPackageDev обратно совместим.
Если вы хотите рассмотреть возможность перехода на YAML (либо из JSON, либо непосредственно из Plist), он предоставляет команду AAAPackageDev: преобразовать в YAML и изменить определение синтаксиса, которая автоматически отформатирует полученный YAML в удобном для вас виде.
Определения синтаксиса Справочник по определениям snytax
© Copyright 2013, Гильермо Лопес-Англада и сообщество Sublime Text. Редакция aab26ddd .
Версии последняя стабильная.
Читайте также: