Я тоже искал эту функциональность, поскольку регулярные выражения очень быстро становятся длинными и сложными, особенно если вы пишете файл tmLanguage в JSON, что заставляет вас экранировать некоторые символы с помощью \\.
It похоже, не поддерживается textmate из коробки. Однако у вас может быть поддержка переменных, если вы не против некоторой предварительной обработки.
Я нашел такое решение при просмотре репозитория Microsoft TypeScript TmLanguage GitHub . Они определяют грамматику Typescript в YAML , которая более удобна для чтения и требует только одного анти-sla sh для экранирования символов. В этом YAML-файле они определяют «переменные» для часто используемых шаблонов, например:
variables:
startOfIdentifier: (?<![_$[:alnum:]])(?:(?<=\.\.\.)|(?<!\.))
endOfIdentifier: (?![_$[:alnum:]])(?:(?=\.\.\.)|(?!\.))
propertyAccess: (?:(\.)|(\?\.(?!\s*[[:digit:]])))
propertyAccessPreIdentifier: \??\.\s*
identifier: '[_$[:alpha:]][_$[:alnum:]]*'
constantIdentifier: '[[:upper:]][_$[:digit:][:upper:]]*'
propertyIdentifier: '\#?{{identifier}}'
constantPropertyIdentifier: '\#?{{constantIdentifier}}'
label: ({{identifier}})\s*(:)
Затем они повторно используют эти «переменные» в определениях шаблонов (или даже в других переменных, если вы посмотрите выше, Переменная label
использует переменную identifier
), например:
enum-declaration:
name: meta.enum.declaration.ts
begin: '{{startOfDeclaration}}(?:\b(const)\s+)?\b(enum)\s+({{identifier}})'
beginCaptures:
'1': { name: keyword.control.export.ts }
'2': { name: storage.modifier.ts}
'3': { name: storage.modifier.ts}
'4': { name: storage.type.enum.ts }
'5': { name: entity.name.type.enum.ts }
И, наконец, они используют скрипт сборки для преобразования этой грамматики YAML в plist или json грамматику. В этом сценарии сборки они удаляют свойство «переменные» из грамматики, поскольку оно не является частью tmLanguage spe c, и они l oop над определениями переменных, чтобы заменить их вхождения ({{variable}}
) в других переменных или begin
, end
, match
паттернов.
function replacePatternVariables(pattern: string, variableReplacers: VariableReplacer[]) {
let result = pattern;
for (const [variableName, value] of variableReplacers) {
result = result.replace(variableName, value);
}
return result;
}
type VariableReplacer = [RegExp, string];
function updateGrammarVariables(grammar: TmGrammar, variables: MapLike<string>) {
delete grammar.variables;
const variableReplacers: VariableReplacer[] = [];
for (const variableName in variables) {
// Replace the pattern with earlier variables
const pattern = replacePatternVariables(variables[variableName], variableReplacers);
variableReplacers.push([new RegExp(`{{${variableName}}}`, "gim"), pattern]);
}
transformGrammarRepository(
grammar,
["begin", "end", "match"],
pattern => replacePatternVariables(pattern, variableReplacers)
);
return grammar;
}
Не совсем то, что вы (и я) искали, но если ваша грамматика достаточно обширна, это поможет. Если грамматика недостаточно велика, я бы не стал использовать эту предварительную обработку.