Что такое монарх
Monarch — это библиотека подсветки синтаксиса, которая поставляется с редактором Monaco Editor, с помощью которой мы можем использовать синтаксис, аналогичный Json, для достиженияПользовательский языкизПодсветка синтаксиса. В этой статье мы познакомимся с использованием Monarch, написав простой пользовательский язык журналов (далее именуемый log).
Начинать
инициализация
monaco.languages.register({ id: 'log' });
monaco.languages.setMonarchTokensProvider('log', monarchObj);
setMonarchTokensProvidermonarchObjЭто содержимое Json, указанное Monarch, которое нам нужно заполнить.
Monarch
Monarch состоит из серии пар ключ-значение Json, имеет множество свойств, наиболее важным из которых являетсяtokenizer属性,我们描述语法的代码就写在这里面。 Начнем с простого примера:
monaco.languages.setMonarchTokensProvider('log', {
tokenizer: {
root:[
[/\d+/,{token:"keyword"}],
[/[a-z]+/,{token:"string"}]
],
}
});
Мы определяем токенизатор вrootАтрибуты,rootдаtokenizerодин изstate, что мы используем для написания правил синтаксического анализа (rule), кудаrule, мы можем написать соответствующий текстрегулярное выражениеИ текст предоставляется для выполнения операции сопоставленияaction,существуетactiontoken class.
В нашем примере мы устанавливаем два правила в корне, которые используются для сопоставленияколичествоа такжеписьмо, после успешного совпадения выполняется соответствующее действие Наконец, в действии мы устанавливаем класс токена, соответствующий тексту:keywordа такжеstring. Окончательный эффект выглядит следующим образом:
.keyword, в Monarch будет слойПерепискаОтдел, ключевое слово соответствует css.mtk8, а строка соответствует css в.mtk5. Следующие классы токенов встроены в Monarch:
identifier entity constructor
operators tag namespace
keyword info-token type
string warn-token predefined
string.escape error-token invalid
comment debug-token
comment.doc regexp
constant attribute
delimiter .[curly,square,parenthesis,angle,array,bracket]
number .[hex,octal,binary,float]
variable .[name,value]
meta .[content]
Однако проблема с выделенным выше кодом все еще существует.
tokenizer: {
root:[
[/\d+/,{token:"keyword"}],
[/[a-zA-Z]+/,{token:"string"}]
],
}
Если наш язык игнорирует регистр, то мы можем напрямую добавитьignoreCaseАтрибуты.
monaco.languages.setMonarchTokensProvider('log', {
ignoreCase: true,
tokenizer: {
root:[
[/\d+/, {token: "keyword"}],
[/[a-z]+/, {token: "string"}]
],
}
});
Окончательный эффект выглядит следующим образом:
язык журнала
Мы хотим, чтобы язык журнала в основном использовался для различения отображения различных типов журналов, общий эффект выглядит следующим образом:
[error], [info], [warning]Как начало строки, представляющей уровень лога. как показано на рисунке,errorЛоги после все будуткрасныйДо следующего уровня журнала.
отметить уровень журнала
Прежде всего, давайте отметим это.[error],[info]
tokenizer: {
root: [
[/^\[error\]/, { token: "custom-error" }],
[/^\[info\]/, { token: "custom-info" }],
[/^\[warning\]/, { token: "custom-warning" }]
]
}
//设置含有custom-error等token class的主题
monaco.editor.defineTheme('logTheme', {
base: 'vs',
inherit: true,
rules: [
{ token: 'custom-info', foreground: '808080' },
{ token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },
{ token: 'custom-warning', foreground: 'FFA500' }
]
});
monaco.editor.create(document.getElementById("container"), {
theme: 'logTheme',
value: getCode(),
language: 'log'
});
[error]отметить какcustom-error,[info]отметить какcustom-info,[warning]отметить какcustom-warning. Мы обнаружили, что эти правила похожи, поэтому мы можем найти способ их объединить.
tokenizer: {
root: [
[/^\[(\w+)\]/, { token: "custom-$1" }]
]
}
Здесь мы используем знак доллара$, который представляет количество совпадений с регулярным выражением,$0Представляет все совпадающие элементы (например: [ошибка]),$1Представляет получение первого совпадения (например, ошибка). Вышеприведенный код передает тип журнала в качестве класса токена параметра, который аналогиченcustom-Сделайте строчку, которые составляют конечный класс токена, например,custom-error.
error,info,warning[debug],[test]cases.
{ cases: { guard1: action1, ..., guardN: actionN } }
casesи обычныйif ,else ifСинтаксис такой же, вы можете написать несколько условий оценки (guard), то согласноguardвыполнить соответствующиеaction.
guardПодобно регулярным выражениям, функция должна сопоставлять текст, если он не начинается с@или$В начале он обычное регулярное выражение, но когда он начинается с@или$В начале он былВ прямом смыслеОхранник.
защита имеет фиксированную структуру[pat][op]match,patпредставлятьсоответствующий текст,opпредставляеткомпаратор,matchЭто длячто сравнивать.
patк$$1$#$0От имени всего подходящего текста. Кроме того, мы также можем использовать$Sn$S0От имениroot.
opа такжеmatchНемного сложнее, это может быть несколько элементов
- ~regex or !~regex: соответствует/не соответствует обычному
- @attribute or !@attribute: соответствует/не соответствует атрибуту.Атрибут определяется на корневом уровне Monarch, который может быть массивом, строкой или обычным.
- ==str or !=str: сопоставить/не сопоставить строку
- @default: соответствует регистру по умолчанию
- @eos: конец строки, совпадение успешно
С помощью этих инструментов мы можем затем написать наш выделенный код
{
keywords: ['error', 'info', 'warning'],
tokenizer: {
root: [
[/^\[(\w+)\]/, {
cases: {
"$1@keywords": { token: 'custom-$1' },
"@default": { token: "string" }
}
}]
]
}
}
Здесь мы использовали$1@keywordsсудитьтип журнала ($1)Существует ли вkeywordsВ массиве он также используется.@default来匹配未定义的日志类型。 Окончательный эффект выглядит следующим образом:
пометить журнал
tokenizer: {
root: [
[/^\[(\w+)\]/, {
cases: {
"$1@keywords": {token:'custom-$1', next:"@text.$1"},
"@default":'string'
}
}],
],
text:[
[/^\[(\w+)\]/,{token:"@rematch",next:"@pop"}],
[/.*/,{token:"custom-$S2"}]
]
}
Здесь впервые былоnext: "@text.$1", Значениетекущее корневое состояниепрыгать вtext state, и положиКорневое состояние помещается в стек токенизатора,существуетtext state, мы можем пройтиnext:@popвернуться к первому в стекеstate, который является нашимroot state.
Вот еще один@rematch, что означает, что текущий текст совпал, но ничего не делать, пусть последующийruleснова совпадать.
Подводя итоги, логика вышеуказанного кодасоответствовать типу журналаПосле этого мыВступил вtext state,существуетtext stateМы будемПоследующий текст (.*)отмечены как иТот же класс токена типа журналаТег типа журналаПосле этого используйте@rematchа также@popВернуться кroot stateПроведите матч еще раз. Эффект следующий:
{
keywords: ['error', 'warning', 'info'],
header: /\[(\w+)\]/,
tokenizer: {
root: [
[/^@header/, {
cases: {
"$1@keywords": { token: 'custom-$1', next: "@text.$1" },
"@default": 'string'
}
}],
],
text: [
[/^@header/, { token: "@rematch", next: "@pop" }],
[/.*/, { token: "custom-$S2" }]
]
}
}
мы будемРегулярное выражение для соответствия типу журналаизвлечь как единое целоеheader, то через@来嵌入。 Но здесь@а такжеguardиз@другой, онПоддерживаются только регулярные выражения,а такжеТип массива не поддерживается.
конец
В этой статье представлены основные понятия и использование Monarch, но объем ограничен. В этой статье не могут быть представлены другие функции, предоставляемые Monarch, такие как сопоставление скобок, встраивание языка и т. д., и есть много деталей, которые не перечислены. заинтересованы, хотите углубленно изучить, можете.