Files

3217 lines
98 KiB
JavaScript

// src/utils.ts
function clone(something) {
return doClone(something);
}
function doClone(something) {
if (Array.isArray(something)) {
return cloneArray(something);
}
if (something instanceof RegExp) {
return something;
}
if (typeof something === "object") {
return cloneObj(something);
}
return something;
}
function cloneArray(arr) {
let r = [];
for (let i = 0, len = arr.length; i < len; i++) {
r[i] = doClone(arr[i]);
}
return r;
}
function cloneObj(obj) {
let r = {};
for (let key in obj) {
r[key] = doClone(obj[key]);
}
return r;
}
function mergeObjects(target, ...sources) {
sources.forEach((source) => {
for (let key in source) {
target[key] = source[key];
}
});
return target;
}
function basename(path) {
const idx = ~path.lastIndexOf("/") || ~path.lastIndexOf("\\");
if (idx === 0) {
return path;
} else if (~idx === path.length - 1) {
return basename(path.substring(0, path.length - 1));
} else {
return path.substr(~idx + 1);
}
}
var CAPTURING_REGEX_SOURCE = /\$(\d+)|\${(\d+):\/(downcase|upcase)}/g;
var RegexSource = class {
static hasCaptures(regexSource) {
if (regexSource === null) {
return false;
}
CAPTURING_REGEX_SOURCE.lastIndex = 0;
return CAPTURING_REGEX_SOURCE.test(regexSource);
}
static replaceCaptures(regexSource, captureSource, captureIndices) {
return regexSource.replace(CAPTURING_REGEX_SOURCE, (match, index, commandIndex, command) => {
let capture = captureIndices[parseInt(index || commandIndex, 10)];
if (capture) {
let result = captureSource.substring(capture.start, capture.end);
while (result[0] === ".") {
result = result.substring(1);
}
switch (command) {
case "downcase":
return result.toLowerCase();
case "upcase":
return result.toUpperCase();
default:
return result;
}
} else {
return match;
}
});
}
};
function strcmp(a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
function strArrCmp(a, b) {
if (a === null && b === null) {
return 0;
}
if (!a) {
return -1;
}
if (!b) {
return 1;
}
let len1 = a.length;
let len2 = b.length;
if (len1 === len2) {
for (let i = 0; i < len1; i++) {
let res = strcmp(a[i], b[i]);
if (res !== 0) {
return res;
}
}
return 0;
}
return len1 - len2;
}
function isValidHexColor(hex) {
if (/^#[0-9a-f]{6}$/i.test(hex)) {
return true;
}
if (/^#[0-9a-f]{8}$/i.test(hex)) {
return true;
}
if (/^#[0-9a-f]{3}$/i.test(hex)) {
return true;
}
if (/^#[0-9a-f]{4}$/i.test(hex)) {
return true;
}
return false;
}
function escapeRegExpCharacters(value) {
return value.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, "\\$&");
}
var CachedFn = class {
constructor(fn) {
this.fn = fn;
}
cache = /* @__PURE__ */ new Map();
get(key) {
if (this.cache.has(key)) {
return this.cache.get(key);
}
const value = this.fn(key);
this.cache.set(key, value);
return value;
}
};
// src/theme.ts
var Theme = class {
constructor(_colorMap, _defaults, _root) {
this._colorMap = _colorMap;
this._defaults = _defaults;
this._root = _root;
}
static createFromRawTheme(source, colorMap) {
return this.createFromParsedTheme(parseTheme(source), colorMap);
}
static createFromParsedTheme(source, colorMap) {
return resolveParsedThemeRules(source, colorMap);
}
_cachedMatchRoot = new CachedFn(
(scopeName) => this._root.match(scopeName)
);
getColorMap() {
return this._colorMap.getColorMap();
}
getDefaults() {
return this._defaults;
}
match(scopePath) {
if (scopePath === null) {
return this._defaults;
}
const scopeName = scopePath.scopeName;
const matchingTrieElements = this._cachedMatchRoot.get(scopeName);
const effectiveRule = matchingTrieElements.find(
(v) => _scopePathMatchesParentScopes(scopePath.parent, v.parentScopes)
);
if (!effectiveRule) {
return null;
}
return new StyleAttributes(
effectiveRule.fontStyle,
effectiveRule.foreground,
effectiveRule.background
);
}
};
var ScopeStack = class _ScopeStack {
constructor(parent, scopeName) {
this.parent = parent;
this.scopeName = scopeName;
}
static push(path, scopeNames) {
for (const name of scopeNames) {
path = new _ScopeStack(path, name);
}
return path;
}
static from(...segments) {
let result = null;
for (let i = 0; i < segments.length; i++) {
result = new _ScopeStack(result, segments[i]);
}
return result;
}
push(scopeName) {
return new _ScopeStack(this, scopeName);
}
getSegments() {
let item = this;
const result = [];
while (item) {
result.push(item.scopeName);
item = item.parent;
}
result.reverse();
return result;
}
toString() {
return this.getSegments().join(" ");
}
extends(other) {
if (this === other) {
return true;
}
if (this.parent === null) {
return false;
}
return this.parent.extends(other);
}
getExtensionIfDefined(base) {
const result = [];
let item = this;
while (item && item !== base) {
result.push(item.scopeName);
item = item.parent;
}
return item === base ? result.reverse() : void 0;
}
};
function _scopePathMatchesParentScopes(scopePath, parentScopes) {
if (parentScopes.length === 0) {
return true;
}
for (let index = 0; index < parentScopes.length; index++) {
let scopePattern = parentScopes[index];
let scopeMustMatch = false;
if (scopePattern === ">") {
if (index === parentScopes.length - 1) {
return false;
}
scopePattern = parentScopes[++index];
scopeMustMatch = true;
}
while (scopePath) {
if (_matchesScope(scopePath.scopeName, scopePattern)) {
break;
}
if (scopeMustMatch) {
return false;
}
scopePath = scopePath.parent;
}
if (!scopePath) {
return false;
}
scopePath = scopePath.parent;
}
return true;
}
function _matchesScope(scopeName, scopePattern) {
return scopePattern === scopeName || scopeName.startsWith(scopePattern) && scopeName[scopePattern.length] === ".";
}
var StyleAttributes = class {
constructor(fontStyle, foregroundId, backgroundId) {
this.fontStyle = fontStyle;
this.foregroundId = foregroundId;
this.backgroundId = backgroundId;
}
};
function parseTheme(source) {
if (!source) {
return [];
}
if (!source.settings || !Array.isArray(source.settings)) {
return [];
}
let settings = source.settings;
let result = [], resultLen = 0;
for (let i = 0, len = settings.length; i < len; i++) {
let entry = settings[i];
if (!entry.settings) {
continue;
}
let scopes;
if (typeof entry.scope === "string") {
let _scope = entry.scope;
_scope = _scope.replace(/^[,]+/, "");
_scope = _scope.replace(/[,]+$/, "");
scopes = _scope.split(",");
} else if (Array.isArray(entry.scope)) {
scopes = entry.scope;
} else {
scopes = [""];
}
let fontStyle = -1 /* NotSet */;
if (typeof entry.settings.fontStyle === "string") {
fontStyle = 0 /* None */;
let segments = entry.settings.fontStyle.split(" ");
for (let j = 0, lenJ = segments.length; j < lenJ; j++) {
let segment = segments[j];
switch (segment) {
case "italic":
fontStyle = fontStyle | 1 /* Italic */;
break;
case "bold":
fontStyle = fontStyle | 2 /* Bold */;
break;
case "underline":
fontStyle = fontStyle | 4 /* Underline */;
break;
case "strikethrough":
fontStyle = fontStyle | 8 /* Strikethrough */;
break;
}
}
}
let foreground = null;
if (typeof entry.settings.foreground === "string" && isValidHexColor(entry.settings.foreground)) {
foreground = entry.settings.foreground;
}
let background = null;
if (typeof entry.settings.background === "string" && isValidHexColor(entry.settings.background)) {
background = entry.settings.background;
}
for (let j = 0, lenJ = scopes.length; j < lenJ; j++) {
let _scope = scopes[j].trim();
let segments = _scope.split(" ");
let scope = segments[segments.length - 1];
let parentScopes = null;
if (segments.length > 1) {
parentScopes = segments.slice(0, segments.length - 1);
parentScopes.reverse();
}
result[resultLen++] = new ParsedThemeRule(
scope,
parentScopes,
i,
fontStyle,
foreground,
background
);
}
}
return result;
}
var ParsedThemeRule = class {
constructor(scope, parentScopes, index, fontStyle, foreground, background) {
this.scope = scope;
this.parentScopes = parentScopes;
this.index = index;
this.fontStyle = fontStyle;
this.foreground = foreground;
this.background = background;
}
};
var FontStyle = /* @__PURE__ */ ((FontStyle2) => {
FontStyle2[FontStyle2["NotSet"] = -1] = "NotSet";
FontStyle2[FontStyle2["None"] = 0] = "None";
FontStyle2[FontStyle2["Italic"] = 1] = "Italic";
FontStyle2[FontStyle2["Bold"] = 2] = "Bold";
FontStyle2[FontStyle2["Underline"] = 4] = "Underline";
FontStyle2[FontStyle2["Strikethrough"] = 8] = "Strikethrough";
return FontStyle2;
})(FontStyle || {});
function resolveParsedThemeRules(parsedThemeRules, _colorMap) {
parsedThemeRules.sort((a, b) => {
let r = strcmp(a.scope, b.scope);
if (r !== 0) {
return r;
}
r = strArrCmp(a.parentScopes, b.parentScopes);
if (r !== 0) {
return r;
}
return a.index - b.index;
});
let defaultFontStyle = 0 /* None */;
let defaultForeground = "#000000";
let defaultBackground = "#ffffff";
while (parsedThemeRules.length >= 1 && parsedThemeRules[0].scope === "") {
let incomingDefaults = parsedThemeRules.shift();
if (incomingDefaults.fontStyle !== -1 /* NotSet */) {
defaultFontStyle = incomingDefaults.fontStyle;
}
if (incomingDefaults.foreground !== null) {
defaultForeground = incomingDefaults.foreground;
}
if (incomingDefaults.background !== null) {
defaultBackground = incomingDefaults.background;
}
}
let colorMap = new ColorMap(_colorMap);
let defaults = new StyleAttributes(defaultFontStyle, colorMap.getId(defaultForeground), colorMap.getId(defaultBackground));
let root = new ThemeTrieElement(new ThemeTrieElementRule(0, null, -1 /* NotSet */, 0, 0), []);
for (let i = 0, len = parsedThemeRules.length; i < len; i++) {
let rule = parsedThemeRules[i];
root.insert(0, rule.scope, rule.parentScopes, rule.fontStyle, colorMap.getId(rule.foreground), colorMap.getId(rule.background));
}
return new Theme(colorMap, defaults, root);
}
var ColorMap = class {
_isFrozen;
_lastColorId;
_id2color;
_color2id;
constructor(_colorMap) {
this._lastColorId = 0;
this._id2color = [];
this._color2id = /* @__PURE__ */ Object.create(null);
if (Array.isArray(_colorMap)) {
this._isFrozen = true;
for (let i = 0, len = _colorMap.length; i < len; i++) {
this._color2id[_colorMap[i]] = i;
this._id2color[i] = _colorMap[i];
}
} else {
this._isFrozen = false;
}
}
getId(color) {
if (color === null) {
return 0;
}
color = color.toUpperCase();
let value = this._color2id[color];
if (value) {
return value;
}
if (this._isFrozen) {
throw new Error(`Missing color in color map - ${color}`);
}
value = ++this._lastColorId;
this._color2id[color] = value;
this._id2color[value] = color;
return value;
}
getColorMap() {
return this._id2color.slice(0);
}
};
var emptyParentScopes = Object.freeze([]);
var ThemeTrieElementRule = class _ThemeTrieElementRule {
scopeDepth;
parentScopes;
fontStyle;
foreground;
background;
constructor(scopeDepth, parentScopes, fontStyle, foreground, background) {
this.scopeDepth = scopeDepth;
this.parentScopes = parentScopes || emptyParentScopes;
this.fontStyle = fontStyle;
this.foreground = foreground;
this.background = background;
}
clone() {
return new _ThemeTrieElementRule(this.scopeDepth, this.parentScopes, this.fontStyle, this.foreground, this.background);
}
static cloneArr(arr) {
let r = [];
for (let i = 0, len = arr.length; i < len; i++) {
r[i] = arr[i].clone();
}
return r;
}
acceptOverwrite(scopeDepth, fontStyle, foreground, background) {
if (this.scopeDepth > scopeDepth) {
console.log("how did this happen?");
} else {
this.scopeDepth = scopeDepth;
}
if (fontStyle !== -1 /* NotSet */) {
this.fontStyle = fontStyle;
}
if (foreground !== 0) {
this.foreground = foreground;
}
if (background !== 0) {
this.background = background;
}
}
};
var ThemeTrieElement = class _ThemeTrieElement {
constructor(_mainRule, rulesWithParentScopes = [], _children = {}) {
this._mainRule = _mainRule;
this._children = _children;
this._rulesWithParentScopes = rulesWithParentScopes;
}
_rulesWithParentScopes;
static _cmpBySpecificity(a, b) {
if (a.scopeDepth !== b.scopeDepth) {
return b.scopeDepth - a.scopeDepth;
}
let aParentIndex = 0;
let bParentIndex = 0;
while (true) {
if (a.parentScopes[aParentIndex] === ">") {
aParentIndex++;
}
if (b.parentScopes[bParentIndex] === ">") {
bParentIndex++;
}
if (aParentIndex >= a.parentScopes.length || bParentIndex >= b.parentScopes.length) {
break;
}
const parentScopeLengthDiff = b.parentScopes[bParentIndex].length - a.parentScopes[aParentIndex].length;
if (parentScopeLengthDiff !== 0) {
return parentScopeLengthDiff;
}
aParentIndex++;
bParentIndex++;
}
return b.parentScopes.length - a.parentScopes.length;
}
match(scope) {
if (scope !== "") {
let dotIndex = scope.indexOf(".");
let head;
let tail;
if (dotIndex === -1) {
head = scope;
tail = "";
} else {
head = scope.substring(0, dotIndex);
tail = scope.substring(dotIndex + 1);
}
if (this._children.hasOwnProperty(head)) {
return this._children[head].match(tail);
}
}
const rules = this._rulesWithParentScopes.concat(this._mainRule);
rules.sort(_ThemeTrieElement._cmpBySpecificity);
return rules;
}
insert(scopeDepth, scope, parentScopes, fontStyle, foreground, background) {
if (scope === "") {
this._doInsertHere(scopeDepth, parentScopes, fontStyle, foreground, background);
return;
}
let dotIndex = scope.indexOf(".");
let head;
let tail;
if (dotIndex === -1) {
head = scope;
tail = "";
} else {
head = scope.substring(0, dotIndex);
tail = scope.substring(dotIndex + 1);
}
let child;
if (this._children.hasOwnProperty(head)) {
child = this._children[head];
} else {
child = new _ThemeTrieElement(this._mainRule.clone(), ThemeTrieElementRule.cloneArr(this._rulesWithParentScopes));
this._children[head] = child;
}
child.insert(scopeDepth + 1, tail, parentScopes, fontStyle, foreground, background);
}
_doInsertHere(scopeDepth, parentScopes, fontStyle, foreground, background) {
if (parentScopes === null) {
this._mainRule.acceptOverwrite(scopeDepth, fontStyle, foreground, background);
return;
}
for (let i = 0, len = this._rulesWithParentScopes.length; i < len; i++) {
let rule = this._rulesWithParentScopes[i];
if (strArrCmp(rule.parentScopes, parentScopes) === 0) {
rule.acceptOverwrite(scopeDepth, fontStyle, foreground, background);
return;
}
}
if (fontStyle === -1 /* NotSet */) {
fontStyle = this._mainRule.fontStyle;
}
if (foreground === 0) {
foreground = this._mainRule.foreground;
}
if (background === 0) {
background = this._mainRule.background;
}
this._rulesWithParentScopes.push(new ThemeTrieElementRule(scopeDepth, parentScopes, fontStyle, foreground, background));
}
};
// src/encodedTokenAttributes.ts
var EncodedTokenMetadata = class _EncodedTokenMetadata {
static toBinaryStr(encodedTokenAttributes) {
return encodedTokenAttributes.toString(2).padStart(32, "0");
}
static print(encodedTokenAttributes) {
const languageId = _EncodedTokenMetadata.getLanguageId(encodedTokenAttributes);
const tokenType = _EncodedTokenMetadata.getTokenType(encodedTokenAttributes);
const fontStyle = _EncodedTokenMetadata.getFontStyle(encodedTokenAttributes);
const foreground = _EncodedTokenMetadata.getForeground(encodedTokenAttributes);
const background = _EncodedTokenMetadata.getBackground(encodedTokenAttributes);
console.log({
languageId,
tokenType,
fontStyle,
foreground,
background
});
}
static getLanguageId(encodedTokenAttributes) {
return (encodedTokenAttributes & 255 /* LANGUAGEID_MASK */) >>> 0 /* LANGUAGEID_OFFSET */;
}
static getTokenType(encodedTokenAttributes) {
return (encodedTokenAttributes & 768 /* TOKEN_TYPE_MASK */) >>> 8 /* TOKEN_TYPE_OFFSET */;
}
static containsBalancedBrackets(encodedTokenAttributes) {
return (encodedTokenAttributes & 1024 /* BALANCED_BRACKETS_MASK */) !== 0;
}
static getFontStyle(encodedTokenAttributes) {
return (encodedTokenAttributes & 30720 /* FONT_STYLE_MASK */) >>> 11 /* FONT_STYLE_OFFSET */;
}
static getForeground(encodedTokenAttributes) {
return (encodedTokenAttributes & 16744448 /* FOREGROUND_MASK */) >>> 15 /* FOREGROUND_OFFSET */;
}
static getBackground(encodedTokenAttributes) {
return (encodedTokenAttributes & 4278190080 /* BACKGROUND_MASK */) >>> 24 /* BACKGROUND_OFFSET */;
}
/**
* Updates the fields in `metadata`.
* A value of `0`, `NotSet` or `null` indicates that the corresponding field should be left as is.
*/
static set(encodedTokenAttributes, languageId, tokenType, containsBalancedBrackets, fontStyle, foreground, background) {
let _languageId = _EncodedTokenMetadata.getLanguageId(encodedTokenAttributes);
let _tokenType = _EncodedTokenMetadata.getTokenType(encodedTokenAttributes);
let _containsBalancedBracketsBit = _EncodedTokenMetadata.containsBalancedBrackets(encodedTokenAttributes) ? 1 : 0;
let _fontStyle = _EncodedTokenMetadata.getFontStyle(encodedTokenAttributes);
let _foreground = _EncodedTokenMetadata.getForeground(encodedTokenAttributes);
let _background = _EncodedTokenMetadata.getBackground(encodedTokenAttributes);
if (languageId !== 0) {
_languageId = languageId;
}
if (tokenType !== 8 /* NotSet */) {
_tokenType = fromOptionalTokenType(tokenType);
}
if (containsBalancedBrackets !== null) {
_containsBalancedBracketsBit = containsBalancedBrackets ? 1 : 0;
}
if (fontStyle !== -1 /* NotSet */) {
_fontStyle = fontStyle;
}
if (foreground !== 0) {
_foreground = foreground;
}
if (background !== 0) {
_background = background;
}
return (_languageId << 0 /* LANGUAGEID_OFFSET */ | _tokenType << 8 /* TOKEN_TYPE_OFFSET */ | _containsBalancedBracketsBit << 10 /* BALANCED_BRACKETS_OFFSET */ | _fontStyle << 11 /* FONT_STYLE_OFFSET */ | _foreground << 15 /* FOREGROUND_OFFSET */ | _background << 24 /* BACKGROUND_OFFSET */) >>> 0;
}
};
function toOptionalTokenType(standardType) {
return standardType;
}
function fromOptionalTokenType(standardType) {
return standardType;
}
// src/matcher.ts
function createMatchers(selector, matchesName) {
const results = [];
const tokenizer = newTokenizer(selector);
let token = tokenizer.next();
while (token !== null) {
let priority = 0;
if (token.length === 2 && token.charAt(1) === ":") {
switch (token.charAt(0)) {
case "R":
priority = 1;
break;
case "L":
priority = -1;
break;
default:
console.log(`Unknown priority ${token} in scope selector`);
}
token = tokenizer.next();
}
let matcher = parseConjunction();
results.push({ matcher, priority });
if (token !== ",") {
break;
}
token = tokenizer.next();
}
return results;
function parseOperand() {
if (token === "-") {
token = tokenizer.next();
const expressionToNegate = parseOperand();
return (matcherInput) => !!expressionToNegate && !expressionToNegate(matcherInput);
}
if (token === "(") {
token = tokenizer.next();
const expressionInParents = parseInnerExpression();
if (token === ")") {
token = tokenizer.next();
}
return expressionInParents;
}
if (isIdentifier(token)) {
const identifiers = [];
do {
identifiers.push(token);
token = tokenizer.next();
} while (isIdentifier(token));
return (matcherInput) => matchesName(identifiers, matcherInput);
}
return null;
}
function parseConjunction() {
const matchers = [];
let matcher = parseOperand();
while (matcher) {
matchers.push(matcher);
matcher = parseOperand();
}
return (matcherInput) => matchers.every((matcher2) => matcher2(matcherInput));
}
function parseInnerExpression() {
const matchers = [];
let matcher = parseConjunction();
while (matcher) {
matchers.push(matcher);
if (token === "|" || token === ",") {
do {
token = tokenizer.next();
} while (token === "|" || token === ",");
} else {
break;
}
matcher = parseConjunction();
}
return (matcherInput) => matchers.some((matcher2) => matcher2(matcherInput));
}
}
function isIdentifier(token) {
return !!token && !!token.match(/[\w\.:]+/);
}
function newTokenizer(input) {
let regex = /([LR]:|[\w\.:][\w\.:\-]*|[\,\|\-\(\)])/g;
let match = regex.exec(input);
return {
next: () => {
if (!match) {
return null;
}
const res = match[0];
match = regex.exec(input);
return res;
}
};
}
// src/onigLib.ts
var FindOption = /* @__PURE__ */ ((FindOption2) => {
FindOption2[FindOption2["None"] = 0] = "None";
FindOption2[FindOption2["NotBeginString"] = 1] = "NotBeginString";
FindOption2[FindOption2["NotEndString"] = 2] = "NotEndString";
FindOption2[FindOption2["NotBeginPosition"] = 4] = "NotBeginPosition";
FindOption2[FindOption2["DebugCall"] = 8] = "DebugCall";
return FindOption2;
})(FindOption || {});
function disposeOnigString(str) {
if (typeof str.dispose === "function") {
str.dispose();
}
}
// src/grammar/grammarDependencies.ts
var TopLevelRuleReference = class {
constructor(scopeName) {
this.scopeName = scopeName;
}
toKey() {
return this.scopeName;
}
};
var TopLevelRepositoryRuleReference = class {
constructor(scopeName, ruleName) {
this.scopeName = scopeName;
this.ruleName = ruleName;
}
toKey() {
return `${this.scopeName}#${this.ruleName}`;
}
};
var ExternalReferenceCollector = class {
_references = [];
_seenReferenceKeys = /* @__PURE__ */ new Set();
get references() {
return this._references;
}
visitedRule = /* @__PURE__ */ new Set();
add(reference) {
const key = reference.toKey();
if (this._seenReferenceKeys.has(key)) {
return;
}
this._seenReferenceKeys.add(key);
this._references.push(reference);
}
};
var ScopeDependencyProcessor = class {
constructor(repo, initialScopeName) {
this.repo = repo;
this.initialScopeName = initialScopeName;
this.seenFullScopeRequests.add(this.initialScopeName);
this.Q = [new TopLevelRuleReference(this.initialScopeName)];
}
seenFullScopeRequests = /* @__PURE__ */ new Set();
seenPartialScopeRequests = /* @__PURE__ */ new Set();
Q;
processQueue() {
const q = this.Q;
this.Q = [];
const deps = new ExternalReferenceCollector();
for (const dep of q) {
collectReferencesOfReference(dep, this.initialScopeName, this.repo, deps);
}
for (const dep of deps.references) {
if (dep instanceof TopLevelRuleReference) {
if (this.seenFullScopeRequests.has(dep.scopeName)) {
continue;
}
this.seenFullScopeRequests.add(dep.scopeName);
this.Q.push(dep);
} else {
if (this.seenFullScopeRequests.has(dep.scopeName)) {
continue;
}
if (this.seenPartialScopeRequests.has(dep.toKey())) {
continue;
}
this.seenPartialScopeRequests.add(dep.toKey());
this.Q.push(dep);
}
}
}
};
function collectReferencesOfReference(reference, baseGrammarScopeName, repo, result) {
const selfGrammar = repo.lookup(reference.scopeName);
if (!selfGrammar) {
if (reference.scopeName === baseGrammarScopeName) {
throw new Error(`No grammar provided for <${baseGrammarScopeName}>`);
}
return;
}
const baseGrammar = repo.lookup(baseGrammarScopeName);
if (reference instanceof TopLevelRuleReference) {
collectExternalReferencesInTopLevelRule({ baseGrammar, selfGrammar }, result);
} else {
collectExternalReferencesInTopLevelRepositoryRule(
reference.ruleName,
{ baseGrammar, selfGrammar, repository: selfGrammar.repository },
result
);
}
const injections = repo.injections(reference.scopeName);
if (injections) {
for (const injection of injections) {
result.add(new TopLevelRuleReference(injection));
}
}
}
function collectExternalReferencesInTopLevelRepositoryRule(ruleName, context, result) {
if (context.repository && context.repository[ruleName]) {
const rule = context.repository[ruleName];
collectExternalReferencesInRules([rule], context, result);
}
}
function collectExternalReferencesInTopLevelRule(context, result) {
if (context.selfGrammar.patterns && Array.isArray(context.selfGrammar.patterns)) {
collectExternalReferencesInRules(
context.selfGrammar.patterns,
{ ...context, repository: context.selfGrammar.repository },
result
);
}
if (context.selfGrammar.injections) {
collectExternalReferencesInRules(
Object.values(context.selfGrammar.injections),
{ ...context, repository: context.selfGrammar.repository },
result
);
}
}
function collectExternalReferencesInRules(rules, context, result) {
for (const rule of rules) {
if (result.visitedRule.has(rule)) {
continue;
}
result.visitedRule.add(rule);
const patternRepository = rule.repository ? mergeObjects({}, context.repository, rule.repository) : context.repository;
if (Array.isArray(rule.patterns)) {
collectExternalReferencesInRules(rule.patterns, { ...context, repository: patternRepository }, result);
}
const include = rule.include;
if (!include) {
continue;
}
const reference = parseInclude(include);
switch (reference.kind) {
case 0 /* Base */:
collectExternalReferencesInTopLevelRule({ ...context, selfGrammar: context.baseGrammar }, result);
break;
case 1 /* Self */:
collectExternalReferencesInTopLevelRule(context, result);
break;
case 2 /* RelativeReference */:
collectExternalReferencesInTopLevelRepositoryRule(reference.ruleName, { ...context, repository: patternRepository }, result);
break;
case 3 /* TopLevelReference */:
case 4 /* TopLevelRepositoryReference */:
const selfGrammar = reference.scopeName === context.selfGrammar.scopeName ? context.selfGrammar : reference.scopeName === context.baseGrammar.scopeName ? context.baseGrammar : void 0;
if (selfGrammar) {
const newContext = { baseGrammar: context.baseGrammar, selfGrammar, repository: patternRepository };
if (reference.kind === 4 /* TopLevelRepositoryReference */) {
collectExternalReferencesInTopLevelRepositoryRule(reference.ruleName, newContext, result);
} else {
collectExternalReferencesInTopLevelRule(newContext, result);
}
} else {
if (reference.kind === 4 /* TopLevelRepositoryReference */) {
result.add(new TopLevelRepositoryRuleReference(reference.scopeName, reference.ruleName));
} else {
result.add(new TopLevelRuleReference(reference.scopeName));
}
}
break;
}
}
}
var BaseReference = class {
kind = 0 /* Base */;
};
var SelfReference = class {
kind = 1 /* Self */;
};
var RelativeReference = class {
constructor(ruleName) {
this.ruleName = ruleName;
}
kind = 2 /* RelativeReference */;
};
var TopLevelReference = class {
constructor(scopeName) {
this.scopeName = scopeName;
}
kind = 3 /* TopLevelReference */;
};
var TopLevelRepositoryReference = class {
constructor(scopeName, ruleName) {
this.scopeName = scopeName;
this.ruleName = ruleName;
}
kind = 4 /* TopLevelRepositoryReference */;
};
function parseInclude(include) {
if (include === "$base") {
return new BaseReference();
} else if (include === "$self") {
return new SelfReference();
}
const indexOfSharp = include.indexOf("#");
if (indexOfSharp === -1) {
return new TopLevelReference(include);
} else if (indexOfSharp === 0) {
return new RelativeReference(include.substring(1));
} else {
const scopeName = include.substring(0, indexOfSharp);
const ruleName = include.substring(indexOfSharp + 1);
return new TopLevelRepositoryReference(scopeName, ruleName);
}
}
// src/rule.ts
var HAS_BACK_REFERENCES = /\\(\d+)/;
var BACK_REFERENCING_END = /\\(\d+)/g;
var ruleIdSymbol = Symbol("RuleId");
var endRuleId = -1;
var whileRuleId = -2;
function ruleIdFromNumber(id) {
return id;
}
function ruleIdToNumber(id) {
return id;
}
var Rule = class {
$location;
id;
_nameIsCapturing;
_name;
_contentNameIsCapturing;
_contentName;
constructor($location, id, name, contentName) {
this.$location = $location;
this.id = id;
this._name = name || null;
this._nameIsCapturing = RegexSource.hasCaptures(this._name);
this._contentName = contentName || null;
this._contentNameIsCapturing = RegexSource.hasCaptures(this._contentName);
}
get debugName() {
const location = this.$location ? `${basename(this.$location.filename)}:${this.$location.line}` : "unknown";
return `${this.constructor.name}#${this.id} @ ${location}`;
}
getName(lineText, captureIndices) {
if (!this._nameIsCapturing || this._name === null || lineText === null || captureIndices === null) {
return this._name;
}
return RegexSource.replaceCaptures(this._name, lineText, captureIndices);
}
getContentName(lineText, captureIndices) {
if (!this._contentNameIsCapturing || this._contentName === null) {
return this._contentName;
}
return RegexSource.replaceCaptures(this._contentName, lineText, captureIndices);
}
};
var CaptureRule = class extends Rule {
retokenizeCapturedWithRuleId;
constructor($location, id, name, contentName, retokenizeCapturedWithRuleId) {
super($location, id, name, contentName);
this.retokenizeCapturedWithRuleId = retokenizeCapturedWithRuleId;
}
dispose() {
}
collectPatterns(grammar, out) {
throw new Error("Not supported!");
}
compile(grammar, endRegexSource) {
throw new Error("Not supported!");
}
compileAG(grammar, endRegexSource, allowA, allowG) {
throw new Error("Not supported!");
}
};
var MatchRule = class extends Rule {
_match;
captures;
_cachedCompiledPatterns;
constructor($location, id, name, match, captures) {
super($location, id, name, null);
this._match = new RegExpSource(match, this.id);
this.captures = captures;
this._cachedCompiledPatterns = null;
}
dispose() {
if (this._cachedCompiledPatterns) {
this._cachedCompiledPatterns.dispose();
this._cachedCompiledPatterns = null;
}
}
get debugMatchRegExp() {
return `${this._match.source}`;
}
collectPatterns(grammar, out) {
out.push(this._match);
}
compile(grammar, endRegexSource) {
return this._getCachedCompiledPatterns(grammar).compile(grammar);
}
compileAG(grammar, endRegexSource, allowA, allowG) {
return this._getCachedCompiledPatterns(grammar).compileAG(grammar, allowA, allowG);
}
_getCachedCompiledPatterns(grammar) {
if (!this._cachedCompiledPatterns) {
this._cachedCompiledPatterns = new RegExpSourceList();
this.collectPatterns(grammar, this._cachedCompiledPatterns);
}
return this._cachedCompiledPatterns;
}
};
var IncludeOnlyRule = class extends Rule {
hasMissingPatterns;
patterns;
_cachedCompiledPatterns;
constructor($location, id, name, contentName, patterns) {
super($location, id, name, contentName);
this.patterns = patterns.patterns;
this.hasMissingPatterns = patterns.hasMissingPatterns;
this._cachedCompiledPatterns = null;
}
dispose() {
if (this._cachedCompiledPatterns) {
this._cachedCompiledPatterns.dispose();
this._cachedCompiledPatterns = null;
}
}
collectPatterns(grammar, out) {
for (const pattern of this.patterns) {
const rule = grammar.getRule(pattern);
rule.collectPatterns(grammar, out);
}
}
compile(grammar, endRegexSource) {
return this._getCachedCompiledPatterns(grammar).compile(grammar);
}
compileAG(grammar, endRegexSource, allowA, allowG) {
return this._getCachedCompiledPatterns(grammar).compileAG(grammar, allowA, allowG);
}
_getCachedCompiledPatterns(grammar) {
if (!this._cachedCompiledPatterns) {
this._cachedCompiledPatterns = new RegExpSourceList();
this.collectPatterns(grammar, this._cachedCompiledPatterns);
}
return this._cachedCompiledPatterns;
}
};
var BeginEndRule = class extends Rule {
_begin;
beginCaptures;
_end;
endHasBackReferences;
endCaptures;
applyEndPatternLast;
hasMissingPatterns;
patterns;
_cachedCompiledPatterns;
constructor($location, id, name, contentName, begin, beginCaptures, end, endCaptures, applyEndPatternLast, patterns) {
super($location, id, name, contentName);
this._begin = new RegExpSource(begin, this.id);
this.beginCaptures = beginCaptures;
this._end = new RegExpSource(end ? end : "\uFFFF", -1);
this.endHasBackReferences = this._end.hasBackReferences;
this.endCaptures = endCaptures;
this.applyEndPatternLast = applyEndPatternLast || false;
this.patterns = patterns.patterns;
this.hasMissingPatterns = patterns.hasMissingPatterns;
this._cachedCompiledPatterns = null;
}
dispose() {
if (this._cachedCompiledPatterns) {
this._cachedCompiledPatterns.dispose();
this._cachedCompiledPatterns = null;
}
}
get debugBeginRegExp() {
return `${this._begin.source}`;
}
get debugEndRegExp() {
return `${this._end.source}`;
}
getEndWithResolvedBackReferences(lineText, captureIndices) {
return this._end.resolveBackReferences(lineText, captureIndices);
}
collectPatterns(grammar, out) {
out.push(this._begin);
}
compile(grammar, endRegexSource) {
return this._getCachedCompiledPatterns(grammar, endRegexSource).compile(grammar);
}
compileAG(grammar, endRegexSource, allowA, allowG) {
return this._getCachedCompiledPatterns(grammar, endRegexSource).compileAG(grammar, allowA, allowG);
}
_getCachedCompiledPatterns(grammar, endRegexSource) {
if (!this._cachedCompiledPatterns) {
this._cachedCompiledPatterns = new RegExpSourceList();
for (const pattern of this.patterns) {
const rule = grammar.getRule(pattern);
rule.collectPatterns(grammar, this._cachedCompiledPatterns);
}
if (this.applyEndPatternLast) {
this._cachedCompiledPatterns.push(this._end.hasBackReferences ? this._end.clone() : this._end);
} else {
this._cachedCompiledPatterns.unshift(this._end.hasBackReferences ? this._end.clone() : this._end);
}
}
if (this._end.hasBackReferences) {
if (this.applyEndPatternLast) {
this._cachedCompiledPatterns.setSource(this._cachedCompiledPatterns.length() - 1, endRegexSource);
} else {
this._cachedCompiledPatterns.setSource(0, endRegexSource);
}
}
return this._cachedCompiledPatterns;
}
};
var BeginWhileRule = class extends Rule {
_begin;
beginCaptures;
whileCaptures;
_while;
whileHasBackReferences;
hasMissingPatterns;
patterns;
_cachedCompiledPatterns;
_cachedCompiledWhilePatterns;
constructor($location, id, name, contentName, begin, beginCaptures, _while, whileCaptures, patterns) {
super($location, id, name, contentName);
this._begin = new RegExpSource(begin, this.id);
this.beginCaptures = beginCaptures;
this.whileCaptures = whileCaptures;
this._while = new RegExpSource(_while, whileRuleId);
this.whileHasBackReferences = this._while.hasBackReferences;
this.patterns = patterns.patterns;
this.hasMissingPatterns = patterns.hasMissingPatterns;
this._cachedCompiledPatterns = null;
this._cachedCompiledWhilePatterns = null;
}
dispose() {
if (this._cachedCompiledPatterns) {
this._cachedCompiledPatterns.dispose();
this._cachedCompiledPatterns = null;
}
if (this._cachedCompiledWhilePatterns) {
this._cachedCompiledWhilePatterns.dispose();
this._cachedCompiledWhilePatterns = null;
}
}
get debugBeginRegExp() {
return `${this._begin.source}`;
}
get debugWhileRegExp() {
return `${this._while.source}`;
}
getWhileWithResolvedBackReferences(lineText, captureIndices) {
return this._while.resolveBackReferences(lineText, captureIndices);
}
collectPatterns(grammar, out) {
out.push(this._begin);
}
compile(grammar, endRegexSource) {
return this._getCachedCompiledPatterns(grammar).compile(grammar);
}
compileAG(grammar, endRegexSource, allowA, allowG) {
return this._getCachedCompiledPatterns(grammar).compileAG(grammar, allowA, allowG);
}
_getCachedCompiledPatterns(grammar) {
if (!this._cachedCompiledPatterns) {
this._cachedCompiledPatterns = new RegExpSourceList();
for (const pattern of this.patterns) {
const rule = grammar.getRule(pattern);
rule.collectPatterns(grammar, this._cachedCompiledPatterns);
}
}
return this._cachedCompiledPatterns;
}
compileWhile(grammar, endRegexSource) {
return this._getCachedCompiledWhilePatterns(grammar, endRegexSource).compile(grammar);
}
compileWhileAG(grammar, endRegexSource, allowA, allowG) {
return this._getCachedCompiledWhilePatterns(grammar, endRegexSource).compileAG(grammar, allowA, allowG);
}
_getCachedCompiledWhilePatterns(grammar, endRegexSource) {
if (!this._cachedCompiledWhilePatterns) {
this._cachedCompiledWhilePatterns = new RegExpSourceList();
this._cachedCompiledWhilePatterns.push(this._while.hasBackReferences ? this._while.clone() : this._while);
}
if (this._while.hasBackReferences) {
this._cachedCompiledWhilePatterns.setSource(0, endRegexSource ? endRegexSource : "\uFFFF");
}
return this._cachedCompiledWhilePatterns;
}
};
var RuleFactory = class _RuleFactory {
static createCaptureRule(helper, $location, name, contentName, retokenizeCapturedWithRuleId) {
return helper.registerRule((id) => {
return new CaptureRule($location, id, name, contentName, retokenizeCapturedWithRuleId);
});
}
static getCompiledRuleId(desc, helper, repository) {
if (!desc.id) {
helper.registerRule((id) => {
desc.id = id;
if (desc.match) {
return new MatchRule(
desc.$vscodeTextmateLocation,
desc.id,
desc.name,
desc.match,
_RuleFactory._compileCaptures(desc.captures, helper, repository)
);
}
if (typeof desc.begin === "undefined") {
if (desc.repository) {
repository = mergeObjects({}, repository, desc.repository);
}
let patterns = desc.patterns;
if (typeof patterns === "undefined" && desc.include) {
patterns = [{ include: desc.include }];
}
return new IncludeOnlyRule(
desc.$vscodeTextmateLocation,
desc.id,
desc.name,
desc.contentName,
_RuleFactory._compilePatterns(patterns, helper, repository)
);
}
if (desc.while) {
return new BeginWhileRule(
desc.$vscodeTextmateLocation,
desc.id,
desc.name,
desc.contentName,
desc.begin,
_RuleFactory._compileCaptures(desc.beginCaptures || desc.captures, helper, repository),
desc.while,
_RuleFactory._compileCaptures(desc.whileCaptures || desc.captures, helper, repository),
_RuleFactory._compilePatterns(desc.patterns, helper, repository)
);
}
return new BeginEndRule(
desc.$vscodeTextmateLocation,
desc.id,
desc.name,
desc.contentName,
desc.begin,
_RuleFactory._compileCaptures(desc.beginCaptures || desc.captures, helper, repository),
desc.end,
_RuleFactory._compileCaptures(desc.endCaptures || desc.captures, helper, repository),
desc.applyEndPatternLast,
_RuleFactory._compilePatterns(desc.patterns, helper, repository)
);
});
}
return desc.id;
}
static _compileCaptures(captures, helper, repository) {
let r = [];
if (captures) {
let maximumCaptureId = 0;
for (const captureId in captures) {
if (captureId === "$vscodeTextmateLocation") {
continue;
}
const numericCaptureId = parseInt(captureId, 10);
if (numericCaptureId > maximumCaptureId) {
maximumCaptureId = numericCaptureId;
}
}
for (let i = 0; i <= maximumCaptureId; i++) {
r[i] = null;
}
for (const captureId in captures) {
if (captureId === "$vscodeTextmateLocation") {
continue;
}
const numericCaptureId = parseInt(captureId, 10);
let retokenizeCapturedWithRuleId = 0;
if (captures[captureId].patterns) {
retokenizeCapturedWithRuleId = _RuleFactory.getCompiledRuleId(captures[captureId], helper, repository);
}
r[numericCaptureId] = _RuleFactory.createCaptureRule(helper, captures[captureId].$vscodeTextmateLocation, captures[captureId].name, captures[captureId].contentName, retokenizeCapturedWithRuleId);
}
}
return r;
}
static _compilePatterns(patterns, helper, repository) {
let r = [];
if (patterns) {
for (let i = 0, len = patterns.length; i < len; i++) {
const pattern = patterns[i];
let ruleId = -1;
if (pattern.include) {
const reference = parseInclude(pattern.include);
switch (reference.kind) {
case 0 /* Base */:
case 1 /* Self */:
ruleId = _RuleFactory.getCompiledRuleId(repository[pattern.include], helper, repository);
break;
case 2 /* RelativeReference */:
let localIncludedRule = repository[reference.ruleName];
if (localIncludedRule) {
ruleId = _RuleFactory.getCompiledRuleId(localIncludedRule, helper, repository);
} else {
}
break;
case 3 /* TopLevelReference */:
case 4 /* TopLevelRepositoryReference */:
const externalGrammarName = reference.scopeName;
const externalGrammarInclude = reference.kind === 4 /* TopLevelRepositoryReference */ ? reference.ruleName : null;
const externalGrammar = helper.getExternalGrammar(externalGrammarName, repository);
if (externalGrammar) {
if (externalGrammarInclude) {
let externalIncludedRule = externalGrammar.repository[externalGrammarInclude];
if (externalIncludedRule) {
ruleId = _RuleFactory.getCompiledRuleId(externalIncludedRule, helper, externalGrammar.repository);
} else {
}
} else {
ruleId = _RuleFactory.getCompiledRuleId(externalGrammar.repository.$self, helper, externalGrammar.repository);
}
} else {
}
break;
}
} else {
ruleId = _RuleFactory.getCompiledRuleId(pattern, helper, repository);
}
if (ruleId !== -1) {
const rule = helper.getRule(ruleId);
let skipRule = false;
if (rule instanceof IncludeOnlyRule || rule instanceof BeginEndRule || rule instanceof BeginWhileRule) {
if (rule.hasMissingPatterns && rule.patterns.length === 0) {
skipRule = true;
}
}
if (skipRule) {
continue;
}
r.push(ruleId);
}
}
}
return {
patterns: r,
hasMissingPatterns: (patterns ? patterns.length : 0) !== r.length
};
}
};
var RegExpSource = class _RegExpSource {
source;
ruleId;
hasAnchor;
hasBackReferences;
_anchorCache;
constructor(regExpSource, ruleId) {
if (regExpSource && typeof regExpSource === "string") {
const len = regExpSource.length;
let lastPushedPos = 0;
let output = [];
let hasAnchor = false;
for (let pos = 0; pos < len; pos++) {
const ch = regExpSource.charAt(pos);
if (ch === "\\") {
if (pos + 1 < len) {
const nextCh = regExpSource.charAt(pos + 1);
if (nextCh === "z") {
output.push(regExpSource.substring(lastPushedPos, pos));
output.push("$(?!\\n)(?<!\\n)");
lastPushedPos = pos + 2;
} else if (nextCh === "A" || nextCh === "G") {
hasAnchor = true;
}
pos++;
}
}
}
this.hasAnchor = hasAnchor;
if (lastPushedPos === 0) {
this.source = regExpSource;
} else {
output.push(regExpSource.substring(lastPushedPos, len));
this.source = output.join("");
}
} else {
this.hasAnchor = false;
this.source = regExpSource;
}
if (this.hasAnchor) {
this._anchorCache = this._buildAnchorCache();
} else {
this._anchorCache = null;
}
this.ruleId = ruleId;
if (typeof this.source === "string") {
this.hasBackReferences = HAS_BACK_REFERENCES.test(this.source);
} else {
this.hasBackReferences = false;
}
}
clone() {
return new _RegExpSource(this.source, this.ruleId);
}
setSource(newSource) {
if (this.source === newSource) {
return;
}
this.source = newSource;
if (this.hasAnchor) {
this._anchorCache = this._buildAnchorCache();
}
}
resolveBackReferences(lineText, captureIndices) {
if (typeof this.source !== "string") {
throw new Error("This method should only be called if the source is a string");
}
let capturedValues = captureIndices.map((capture) => {
return lineText.substring(capture.start, capture.end);
});
BACK_REFERENCING_END.lastIndex = 0;
return this.source.replace(BACK_REFERENCING_END, (match, g1) => {
return escapeRegExpCharacters(capturedValues[parseInt(g1, 10)] || "");
});
}
_buildAnchorCache() {
if (typeof this.source !== "string") {
throw new Error("This method should only be called if the source is a string");
}
let A0_G0_result = [];
let A0_G1_result = [];
let A1_G0_result = [];
let A1_G1_result = [];
let pos, len, ch, nextCh;
for (pos = 0, len = this.source.length; pos < len; pos++) {
ch = this.source.charAt(pos);
A0_G0_result[pos] = ch;
A0_G1_result[pos] = ch;
A1_G0_result[pos] = ch;
A1_G1_result[pos] = ch;
if (ch === "\\") {
if (pos + 1 < len) {
nextCh = this.source.charAt(pos + 1);
if (nextCh === "A") {
A0_G0_result[pos + 1] = "\uFFFF";
A0_G1_result[pos + 1] = "\uFFFF";
A1_G0_result[pos + 1] = "A";
A1_G1_result[pos + 1] = "A";
} else if (nextCh === "G") {
A0_G0_result[pos + 1] = "\uFFFF";
A0_G1_result[pos + 1] = "G";
A1_G0_result[pos + 1] = "\uFFFF";
A1_G1_result[pos + 1] = "G";
} else {
A0_G0_result[pos + 1] = nextCh;
A0_G1_result[pos + 1] = nextCh;
A1_G0_result[pos + 1] = nextCh;
A1_G1_result[pos + 1] = nextCh;
}
pos++;
}
}
}
return {
A0_G0: A0_G0_result.join(""),
A0_G1: A0_G1_result.join(""),
A1_G0: A1_G0_result.join(""),
A1_G1: A1_G1_result.join("")
};
}
resolveAnchors(allowA, allowG) {
if (!this.hasAnchor || !this._anchorCache || typeof this.source !== "string") {
return this.source;
}
if (allowA) {
if (allowG) {
return this._anchorCache.A1_G1;
} else {
return this._anchorCache.A1_G0;
}
} else {
if (allowG) {
return this._anchorCache.A0_G1;
} else {
return this._anchorCache.A0_G0;
}
}
}
};
var RegExpSourceList = class {
_items;
_hasAnchors;
_cached;
_anchorCache;
constructor() {
this._items = [];
this._hasAnchors = false;
this._cached = null;
this._anchorCache = {
A0_G0: null,
A0_G1: null,
A1_G0: null,
A1_G1: null
};
}
dispose() {
this._disposeCaches();
}
_disposeCaches() {
if (this._cached) {
this._cached.dispose();
this._cached = null;
}
if (this._anchorCache.A0_G0) {
this._anchorCache.A0_G0.dispose();
this._anchorCache.A0_G0 = null;
}
if (this._anchorCache.A0_G1) {
this._anchorCache.A0_G1.dispose();
this._anchorCache.A0_G1 = null;
}
if (this._anchorCache.A1_G0) {
this._anchorCache.A1_G0.dispose();
this._anchorCache.A1_G0 = null;
}
if (this._anchorCache.A1_G1) {
this._anchorCache.A1_G1.dispose();
this._anchorCache.A1_G1 = null;
}
}
push(item) {
this._items.push(item);
this._hasAnchors = this._hasAnchors || item.hasAnchor;
}
unshift(item) {
this._items.unshift(item);
this._hasAnchors = this._hasAnchors || item.hasAnchor;
}
length() {
return this._items.length;
}
setSource(index, newSource) {
if (this._items[index].source !== newSource) {
this._disposeCaches();
this._items[index].setSource(newSource);
}
}
compile(onigLib) {
if (!this._cached) {
let regExps = this._items.map((e) => e.source);
this._cached = new CompiledRule(onigLib, regExps, this._items.map((e) => e.ruleId));
}
return this._cached;
}
compileAG(onigLib, allowA, allowG) {
if (!this._hasAnchors) {
return this.compile(onigLib);
} else {
if (allowA) {
if (allowG) {
if (!this._anchorCache.A1_G1) {
this._anchorCache.A1_G1 = this._resolveAnchors(onigLib, allowA, allowG);
}
return this._anchorCache.A1_G1;
} else {
if (!this._anchorCache.A1_G0) {
this._anchorCache.A1_G0 = this._resolveAnchors(onigLib, allowA, allowG);
}
return this._anchorCache.A1_G0;
}
} else {
if (allowG) {
if (!this._anchorCache.A0_G1) {
this._anchorCache.A0_G1 = this._resolveAnchors(onigLib, allowA, allowG);
}
return this._anchorCache.A0_G1;
} else {
if (!this._anchorCache.A0_G0) {
this._anchorCache.A0_G0 = this._resolveAnchors(onigLib, allowA, allowG);
}
return this._anchorCache.A0_G0;
}
}
}
}
_resolveAnchors(onigLib, allowA, allowG) {
let regExps = this._items.map((e) => e.resolveAnchors(allowA, allowG));
return new CompiledRule(onigLib, regExps, this._items.map((e) => e.ruleId));
}
};
var CompiledRule = class {
constructor(onigLib, regExps, rules) {
this.regExps = regExps;
this.rules = rules;
this.scanner = onigLib.createOnigScanner(regExps);
}
scanner;
dispose() {
if (typeof this.scanner.dispose === "function") {
this.scanner.dispose();
}
}
toString() {
const r = [];
for (let i = 0, len = this.rules.length; i < len; i++) {
r.push(" - " + this.rules[i] + ": " + this.regExps[i]);
}
return r.join("\n");
}
findNextMatchSync(string, startPosition, options) {
const result = this.scanner.findNextMatchSync(string, startPosition, options);
if (!result) {
return null;
}
return {
ruleId: this.rules[result.index],
captureIndices: result.captureIndices
};
}
};
// src/grammar/basicScopesAttributeProvider.ts
var BasicScopeAttributes = class {
constructor(languageId, tokenType) {
this.languageId = languageId;
this.tokenType = tokenType;
}
};
var BasicScopeAttributesProvider = class _BasicScopeAttributesProvider {
_defaultAttributes;
_embeddedLanguagesMatcher;
constructor(initialLanguageId, embeddedLanguages) {
this._defaultAttributes = new BasicScopeAttributes(initialLanguageId, 8 /* NotSet */);
this._embeddedLanguagesMatcher = new ScopeMatcher(Object.entries(embeddedLanguages || {}));
}
getDefaultAttributes() {
return this._defaultAttributes;
}
getBasicScopeAttributes(scopeName) {
if (scopeName === null) {
return _BasicScopeAttributesProvider._NULL_SCOPE_METADATA;
}
return this._getBasicScopeAttributes.get(scopeName);
}
static _NULL_SCOPE_METADATA = new BasicScopeAttributes(0, 0);
_getBasicScopeAttributes = new CachedFn((scopeName) => {
const languageId = this._scopeToLanguage(scopeName);
const standardTokenType = this._toStandardTokenType(scopeName);
return new BasicScopeAttributes(languageId, standardTokenType);
});
/**
* Given a produced TM scope, return the language that token describes or null if unknown.
* e.g. source.html => html, source.css.embedded.html => css, punctuation.definition.tag.html => null
*/
_scopeToLanguage(scope) {
return this._embeddedLanguagesMatcher.match(scope) || 0;
}
_toStandardTokenType(scopeName) {
const m = scopeName.match(_BasicScopeAttributesProvider.STANDARD_TOKEN_TYPE_REGEXP);
if (!m) {
return 8 /* NotSet */;
}
switch (m[1]) {
case "comment":
return 1 /* Comment */;
case "string":
return 2 /* String */;
case "regex":
return 3 /* RegEx */;
case "meta.embedded":
return 0 /* Other */;
}
throw new Error("Unexpected match for standard token type!");
}
static STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex|meta\.embedded)\b/;
};
var ScopeMatcher = class {
values;
scopesRegExp;
constructor(values) {
if (values.length === 0) {
this.values = null;
this.scopesRegExp = null;
} else {
this.values = new Map(values);
const escapedScopes = values.map(
([scopeName, value]) => escapeRegExpCharacters(scopeName)
);
escapedScopes.sort();
escapedScopes.reverse();
this.scopesRegExp = new RegExp(
`^((${escapedScopes.join(")|(")}))($|\\.)`,
""
);
}
}
match(scope) {
if (!this.scopesRegExp) {
return void 0;
}
const m = scope.match(this.scopesRegExp);
if (!m) {
return void 0;
}
return this.values.get(m[1]);
}
};
// src/debug.ts
var DebugFlags = {
InDebugMode: typeof process !== "undefined" && !!process.env["VSCODE_TEXTMATE_DEBUG"]
};
var UseOnigurumaFindOptions = false;
// src/grammar/tokenizeString.ts
var TokenizeStringResult = class {
constructor(stack, stoppedEarly) {
this.stack = stack;
this.stoppedEarly = stoppedEarly;
}
};
function _tokenizeString(grammar, lineText, isFirstLine, linePos, stack, lineTokens, checkWhileConditions, timeLimit) {
const lineLength = lineText.content.length;
let STOP = false;
let anchorPosition = -1;
if (checkWhileConditions) {
const whileCheckResult = _checkWhileConditions(
grammar,
lineText,
isFirstLine,
linePos,
stack,
lineTokens
);
stack = whileCheckResult.stack;
linePos = whileCheckResult.linePos;
isFirstLine = whileCheckResult.isFirstLine;
anchorPosition = whileCheckResult.anchorPosition;
}
const startTime = Date.now();
while (!STOP) {
if (timeLimit !== 0) {
const elapsedTime = Date.now() - startTime;
if (elapsedTime > timeLimit) {
return new TokenizeStringResult(stack, true);
}
}
scanNext();
}
return new TokenizeStringResult(stack, false);
function scanNext() {
if (false) {
console.log("");
console.log(
`@@scanNext ${linePos}: |${lineText.content.substr(linePos).replace(/\n$/, "\\n")}|`
);
}
const r = matchRuleOrInjections(
grammar,
lineText,
isFirstLine,
linePos,
stack,
anchorPosition
);
if (!r) {
lineTokens.produce(stack, lineLength);
STOP = true;
return;
}
const captureIndices = r.captureIndices;
const matchedRuleId = r.matchedRuleId;
const hasAdvanced = captureIndices && captureIndices.length > 0 ? captureIndices[0].end > linePos : false;
if (matchedRuleId === endRuleId) {
const poppedRule = stack.getRule(grammar);
if (false) {
console.log(
" popping " + poppedRule.debugName + " - " + poppedRule.debugEndRegExp
);
}
lineTokens.produce(stack, captureIndices[0].start);
stack = stack.withContentNameScopesList(stack.nameScopesList);
handleCaptures(
grammar,
lineText,
isFirstLine,
stack,
lineTokens,
poppedRule.endCaptures,
captureIndices
);
lineTokens.produce(stack, captureIndices[0].end);
const popped = stack;
stack = stack.parent;
anchorPosition = popped.getAnchorPos();
if (!hasAdvanced && popped.getEnterPos() === linePos) {
if (false) {
console.error(
"[1] - Grammar is in an endless loop - Grammar pushed & popped a rule without advancing"
);
}
stack = popped;
lineTokens.produce(stack, lineLength);
STOP = true;
return;
}
} else {
const _rule = grammar.getRule(matchedRuleId);
lineTokens.produce(stack, captureIndices[0].start);
const beforePush = stack;
const scopeName = _rule.getName(lineText.content, captureIndices);
const nameScopesList = stack.contentNameScopesList.pushAttributed(
scopeName,
grammar
);
stack = stack.push(
matchedRuleId,
linePos,
anchorPosition,
captureIndices[0].end === lineLength,
null,
nameScopesList,
nameScopesList
);
if (_rule instanceof BeginEndRule) {
const pushedRule = _rule;
if (false) {
console.log(
" pushing " + pushedRule.debugName + " - " + pushedRule.debugBeginRegExp
);
}
handleCaptures(
grammar,
lineText,
isFirstLine,
stack,
lineTokens,
pushedRule.beginCaptures,
captureIndices
);
lineTokens.produce(stack, captureIndices[0].end);
anchorPosition = captureIndices[0].end;
const contentName = pushedRule.getContentName(
lineText.content,
captureIndices
);
const contentNameScopesList = nameScopesList.pushAttributed(
contentName,
grammar
);
stack = stack.withContentNameScopesList(contentNameScopesList);
if (pushedRule.endHasBackReferences) {
stack = stack.withEndRule(
pushedRule.getEndWithResolvedBackReferences(
lineText.content,
captureIndices
)
);
}
if (!hasAdvanced && beforePush.hasSameRuleAs(stack)) {
if (false) {
console.error(
"[2] - Grammar is in an endless loop - Grammar pushed the same rule without advancing"
);
}
stack = stack.pop();
lineTokens.produce(stack, lineLength);
STOP = true;
return;
}
} else if (_rule instanceof BeginWhileRule) {
const pushedRule = _rule;
if (false) {
console.log(" pushing " + pushedRule.debugName);
}
handleCaptures(
grammar,
lineText,
isFirstLine,
stack,
lineTokens,
pushedRule.beginCaptures,
captureIndices
);
lineTokens.produce(stack, captureIndices[0].end);
anchorPosition = captureIndices[0].end;
const contentName = pushedRule.getContentName(
lineText.content,
captureIndices
);
const contentNameScopesList = nameScopesList.pushAttributed(
contentName,
grammar
);
stack = stack.withContentNameScopesList(contentNameScopesList);
if (pushedRule.whileHasBackReferences) {
stack = stack.withEndRule(
pushedRule.getWhileWithResolvedBackReferences(
lineText.content,
captureIndices
)
);
}
if (!hasAdvanced && beforePush.hasSameRuleAs(stack)) {
if (false) {
console.error(
"[3] - Grammar is in an endless loop - Grammar pushed the same rule without advancing"
);
}
stack = stack.pop();
lineTokens.produce(stack, lineLength);
STOP = true;
return;
}
} else {
const matchingRule = _rule;
if (false) {
console.log(
" matched " + matchingRule.debugName + " - " + matchingRule.debugMatchRegExp
);
}
handleCaptures(
grammar,
lineText,
isFirstLine,
stack,
lineTokens,
matchingRule.captures,
captureIndices
);
lineTokens.produce(stack, captureIndices[0].end);
stack = stack.pop();
if (!hasAdvanced) {
if (false) {
console.error(
"[4] - Grammar is in an endless loop - Grammar is not advancing, nor is it pushing/popping"
);
}
stack = stack.safePop();
lineTokens.produce(stack, lineLength);
STOP = true;
return;
}
}
}
if (captureIndices[0].end > linePos) {
linePos = captureIndices[0].end;
isFirstLine = false;
}
}
}
function _checkWhileConditions(grammar, lineText, isFirstLine, linePos, stack, lineTokens) {
let anchorPosition = stack.beginRuleCapturedEOL ? 0 : -1;
const whileRules = [];
for (let node = stack; node; node = node.pop()) {
const nodeRule = node.getRule(grammar);
if (nodeRule instanceof BeginWhileRule) {
whileRules.push({
rule: nodeRule,
stack: node
});
}
}
for (let whileRule = whileRules.pop(); whileRule; whileRule = whileRules.pop()) {
const { ruleScanner, findOptions } = prepareRuleWhileSearch(whileRule.rule, grammar, whileRule.stack.endRule, isFirstLine, linePos === anchorPosition);
const r = ruleScanner.findNextMatchSync(lineText, linePos, findOptions);
if (false) {
console.log(" scanning for while rule");
console.log(ruleScanner.toString());
}
if (r) {
const matchedRuleId = r.ruleId;
if (matchedRuleId !== whileRuleId) {
stack = whileRule.stack.pop();
break;
}
if (r.captureIndices && r.captureIndices.length) {
lineTokens.produce(whileRule.stack, r.captureIndices[0].start);
handleCaptures(grammar, lineText, isFirstLine, whileRule.stack, lineTokens, whileRule.rule.whileCaptures, r.captureIndices);
lineTokens.produce(whileRule.stack, r.captureIndices[0].end);
anchorPosition = r.captureIndices[0].end;
if (r.captureIndices[0].end > linePos) {
linePos = r.captureIndices[0].end;
isFirstLine = false;
}
}
} else {
if (false) {
console.log(" popping " + whileRule.rule.debugName + " - " + whileRule.rule.debugWhileRegExp);
}
stack = whileRule.stack.pop();
break;
}
}
return { stack, linePos, anchorPosition, isFirstLine };
}
function matchRuleOrInjections(grammar, lineText, isFirstLine, linePos, stack, anchorPosition) {
const matchResult = matchRule(grammar, lineText, isFirstLine, linePos, stack, anchorPosition);
const injections = grammar.getInjections();
if (injections.length === 0) {
return matchResult;
}
const injectionResult = matchInjections(injections, grammar, lineText, isFirstLine, linePos, stack, anchorPosition);
if (!injectionResult) {
return matchResult;
}
if (!matchResult) {
return injectionResult;
}
const matchResultScore = matchResult.captureIndices[0].start;
const injectionResultScore = injectionResult.captureIndices[0].start;
if (injectionResultScore < matchResultScore || injectionResult.priorityMatch && injectionResultScore === matchResultScore) {
return injectionResult;
}
return matchResult;
}
function matchRule(grammar, lineText, isFirstLine, linePos, stack, anchorPosition) {
const rule = stack.getRule(grammar);
const { ruleScanner, findOptions } = prepareRuleSearch(rule, grammar, stack.endRule, isFirstLine, linePos === anchorPosition);
const r = ruleScanner.findNextMatchSync(lineText, linePos, findOptions);
if (r) {
return {
captureIndices: r.captureIndices,
matchedRuleId: r.ruleId
};
}
return null;
}
function matchInjections(injections, grammar, lineText, isFirstLine, linePos, stack, anchorPosition) {
let bestMatchRating = Number.MAX_VALUE;
let bestMatchCaptureIndices = null;
let bestMatchRuleId;
let bestMatchResultPriority = 0;
const scopes = stack.contentNameScopesList.getScopeNames();
for (let i = 0, len = injections.length; i < len; i++) {
const injection = injections[i];
if (!injection.matcher(scopes)) {
continue;
}
const rule = grammar.getRule(injection.ruleId);
const { ruleScanner, findOptions } = prepareRuleSearch(rule, grammar, null, isFirstLine, linePos === anchorPosition);
const matchResult = ruleScanner.findNextMatchSync(lineText, linePos, findOptions);
if (!matchResult) {
continue;
}
if (false) {
console.log(` matched injection: ${injection.debugSelector}`);
console.log(ruleScanner.toString());
}
const matchRating = matchResult.captureIndices[0].start;
if (matchRating >= bestMatchRating) {
continue;
}
bestMatchRating = matchRating;
bestMatchCaptureIndices = matchResult.captureIndices;
bestMatchRuleId = matchResult.ruleId;
bestMatchResultPriority = injection.priority;
if (bestMatchRating === linePos) {
break;
}
}
if (bestMatchCaptureIndices) {
return {
priorityMatch: bestMatchResultPriority === -1,
captureIndices: bestMatchCaptureIndices,
matchedRuleId: bestMatchRuleId
};
}
return null;
}
function prepareRuleSearch(rule, grammar, endRegexSource, allowA, allowG) {
if (UseOnigurumaFindOptions) {
const ruleScanner2 = rule.compile(grammar, endRegexSource);
const findOptions = getFindOptions(allowA, allowG);
return { ruleScanner: ruleScanner2, findOptions };
}
const ruleScanner = rule.compileAG(grammar, endRegexSource, allowA, allowG);
return { ruleScanner, findOptions: 0 /* None */ };
}
function prepareRuleWhileSearch(rule, grammar, endRegexSource, allowA, allowG) {
if (UseOnigurumaFindOptions) {
const ruleScanner2 = rule.compileWhile(grammar, endRegexSource);
const findOptions = getFindOptions(allowA, allowG);
return { ruleScanner: ruleScanner2, findOptions };
}
const ruleScanner = rule.compileWhileAG(grammar, endRegexSource, allowA, allowG);
return { ruleScanner, findOptions: 0 /* None */ };
}
function getFindOptions(allowA, allowG) {
let options = 0 /* None */;
if (!allowA) {
options |= 1 /* NotBeginString */;
}
if (!allowG) {
options |= 4 /* NotBeginPosition */;
}
return options;
}
function handleCaptures(grammar, lineText, isFirstLine, stack, lineTokens, captures, captureIndices) {
if (captures.length === 0) {
return;
}
const lineTextContent = lineText.content;
const len = Math.min(captures.length, captureIndices.length);
const localStack = [];
const maxEnd = captureIndices[0].end;
for (let i = 0; i < len; i++) {
const captureRule = captures[i];
if (captureRule === null) {
continue;
}
const captureIndex = captureIndices[i];
if (captureIndex.length === 0) {
continue;
}
if (captureIndex.start > maxEnd) {
break;
}
while (localStack.length > 0 && localStack[localStack.length - 1].endPos <= captureIndex.start) {
lineTokens.produceFromScopes(localStack[localStack.length - 1].scopes, localStack[localStack.length - 1].endPos);
localStack.pop();
}
if (localStack.length > 0) {
lineTokens.produceFromScopes(localStack[localStack.length - 1].scopes, captureIndex.start);
} else {
lineTokens.produce(stack, captureIndex.start);
}
if (captureRule.retokenizeCapturedWithRuleId) {
const scopeName = captureRule.getName(lineTextContent, captureIndices);
const nameScopesList = stack.contentNameScopesList.pushAttributed(scopeName, grammar);
const contentName = captureRule.getContentName(lineTextContent, captureIndices);
const contentNameScopesList = nameScopesList.pushAttributed(contentName, grammar);
const stackClone = stack.push(captureRule.retokenizeCapturedWithRuleId, captureIndex.start, -1, false, null, nameScopesList, contentNameScopesList);
const onigSubStr = grammar.createOnigString(lineTextContent.substring(0, captureIndex.end));
_tokenizeString(
grammar,
onigSubStr,
isFirstLine && captureIndex.start === 0,
captureIndex.start,
stackClone,
lineTokens,
false,
/* no time limit */
0
);
disposeOnigString(onigSubStr);
continue;
}
const captureRuleScopeName = captureRule.getName(lineTextContent, captureIndices);
if (captureRuleScopeName !== null) {
const base = localStack.length > 0 ? localStack[localStack.length - 1].scopes : stack.contentNameScopesList;
const captureRuleScopesList = base.pushAttributed(captureRuleScopeName, grammar);
localStack.push(new LocalStackElement(captureRuleScopesList, captureIndex.end));
}
}
while (localStack.length > 0) {
lineTokens.produceFromScopes(localStack[localStack.length - 1].scopes, localStack[localStack.length - 1].endPos);
localStack.pop();
}
}
var LocalStackElement = class {
scopes;
endPos;
constructor(scopes, endPos) {
this.scopes = scopes;
this.endPos = endPos;
}
};
// src/grammar/grammar.ts
function createGrammar(scopeName, grammar, initialLanguage, embeddedLanguages, tokenTypes, balancedBracketSelectors, grammarRepository, onigLib) {
return new Grammar(
scopeName,
grammar,
initialLanguage,
embeddedLanguages,
tokenTypes,
balancedBracketSelectors,
grammarRepository,
onigLib
);
}
function collectInjections(result, selector, rule, ruleFactoryHelper, grammar) {
const matchers = createMatchers(selector, nameMatcher);
const ruleId = RuleFactory.getCompiledRuleId(rule, ruleFactoryHelper, grammar.repository);
for (const matcher of matchers) {
result.push({
debugSelector: selector,
matcher: matcher.matcher,
ruleId,
grammar,
priority: matcher.priority
});
}
}
function nameMatcher(identifers, scopes) {
if (scopes.length < identifers.length) {
return false;
}
let lastIndex = 0;
return identifers.every((identifier) => {
for (let i = lastIndex; i < scopes.length; i++) {
if (scopesAreMatching(scopes[i], identifier)) {
lastIndex = i + 1;
return true;
}
}
return false;
});
}
function scopesAreMatching(thisScopeName, scopeName) {
if (!thisScopeName) {
return false;
}
if (thisScopeName === scopeName) {
return true;
}
const len = scopeName.length;
return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === ".";
}
var Grammar = class {
constructor(_rootScopeName, grammar, initialLanguage, embeddedLanguages, tokenTypes, balancedBracketSelectors, grammarRepository, _onigLib) {
this._rootScopeName = _rootScopeName;
this.balancedBracketSelectors = balancedBracketSelectors;
this._onigLib = _onigLib;
this._basicScopeAttributesProvider = new BasicScopeAttributesProvider(
initialLanguage,
embeddedLanguages
);
this._rootId = -1;
this._lastRuleId = 0;
this._ruleId2desc = [null];
this._includedGrammars = {};
this._grammarRepository = grammarRepository;
this._grammar = initGrammar(grammar, null);
this._injections = null;
this._tokenTypeMatchers = [];
if (tokenTypes) {
for (const selector of Object.keys(tokenTypes)) {
const matchers = createMatchers(selector, nameMatcher);
for (const matcher of matchers) {
this._tokenTypeMatchers.push({
matcher: matcher.matcher,
type: tokenTypes[selector]
});
}
}
}
}
_rootId;
_lastRuleId;
_ruleId2desc;
_includedGrammars;
_grammarRepository;
_grammar;
_injections;
_basicScopeAttributesProvider;
_tokenTypeMatchers;
get themeProvider() {
return this._grammarRepository;
}
dispose() {
for (const rule of this._ruleId2desc) {
if (rule) {
rule.dispose();
}
}
}
createOnigScanner(sources) {
return this._onigLib.createOnigScanner(sources);
}
createOnigString(sources) {
return this._onigLib.createOnigString(sources);
}
getMetadataForScope(scope) {
return this._basicScopeAttributesProvider.getBasicScopeAttributes(scope);
}
_collectInjections() {
const grammarRepository = {
lookup: (scopeName2) => {
if (scopeName2 === this._rootScopeName) {
return this._grammar;
}
return this.getExternalGrammar(scopeName2);
},
injections: (scopeName2) => {
return this._grammarRepository.injections(scopeName2);
}
};
const result = [];
const scopeName = this._rootScopeName;
const grammar = grammarRepository.lookup(scopeName);
if (grammar) {
const rawInjections = grammar.injections;
if (rawInjections) {
for (let expression in rawInjections) {
collectInjections(
result,
expression,
rawInjections[expression],
this,
grammar
);
}
}
const injectionScopeNames = this._grammarRepository.injections(scopeName);
if (injectionScopeNames) {
injectionScopeNames.forEach((injectionScopeName) => {
const injectionGrammar = this.getExternalGrammar(injectionScopeName);
if (injectionGrammar) {
const selector = injectionGrammar.injectionSelector;
if (selector) {
collectInjections(
result,
selector,
injectionGrammar,
this,
injectionGrammar
);
}
}
});
}
}
result.sort((i1, i2) => i1.priority - i2.priority);
return result;
}
getInjections() {
if (this._injections === null) {
this._injections = this._collectInjections();
}
return this._injections;
}
registerRule(factory) {
const id = ++this._lastRuleId;
const result = factory(ruleIdFromNumber(id));
this._ruleId2desc[id] = result;
return result;
}
getRule(ruleId) {
return this._ruleId2desc[ruleIdToNumber(ruleId)];
}
getExternalGrammar(scopeName, repository) {
if (this._includedGrammars[scopeName]) {
return this._includedGrammars[scopeName];
} else if (this._grammarRepository) {
const rawIncludedGrammar = this._grammarRepository.lookup(scopeName);
if (rawIncludedGrammar) {
this._includedGrammars[scopeName] = initGrammar(
rawIncludedGrammar,
repository && repository.$base
);
return this._includedGrammars[scopeName];
}
}
return void 0;
}
tokenizeLine(lineText, prevState, timeLimit = 0) {
const r = this._tokenize(lineText, prevState, false, timeLimit);
return {
tokens: r.lineTokens.getResult(r.ruleStack, r.lineLength),
ruleStack: r.ruleStack,
stoppedEarly: r.stoppedEarly
};
}
tokenizeLine2(lineText, prevState, timeLimit = 0) {
const r = this._tokenize(lineText, prevState, true, timeLimit);
return {
tokens: r.lineTokens.getBinaryResult(r.ruleStack, r.lineLength),
ruleStack: r.ruleStack,
stoppedEarly: r.stoppedEarly
};
}
_tokenize(lineText, prevState, emitBinaryTokens, timeLimit) {
if (this._rootId === -1) {
this._rootId = RuleFactory.getCompiledRuleId(
this._grammar.repository.$self,
this,
this._grammar.repository
);
this.getInjections();
}
let isFirstLine;
if (!prevState || prevState === StateStackImpl.NULL) {
isFirstLine = true;
const rawDefaultMetadata = this._basicScopeAttributesProvider.getDefaultAttributes();
const defaultStyle = this.themeProvider.getDefaults();
const defaultMetadata = EncodedTokenMetadata.set(
0,
rawDefaultMetadata.languageId,
rawDefaultMetadata.tokenType,
null,
defaultStyle.fontStyle,
defaultStyle.foregroundId,
defaultStyle.backgroundId
);
const rootScopeName = this.getRule(this._rootId).getName(
null,
null
);
let scopeList;
if (rootScopeName) {
scopeList = AttributedScopeStack.createRootAndLookUpScopeName(
rootScopeName,
defaultMetadata,
this
);
} else {
scopeList = AttributedScopeStack.createRoot(
"unknown",
defaultMetadata
);
}
prevState = new StateStackImpl(
null,
this._rootId,
-1,
-1,
false,
null,
scopeList,
scopeList
);
} else {
isFirstLine = false;
prevState.reset();
}
lineText = lineText + "\n";
const onigLineText = this.createOnigString(lineText);
const lineLength = onigLineText.content.length;
const lineTokens = new LineTokens(
emitBinaryTokens,
lineText,
this._tokenTypeMatchers,
this.balancedBracketSelectors
);
const r = _tokenizeString(
this,
onigLineText,
isFirstLine,
0,
prevState,
lineTokens,
true,
timeLimit
);
disposeOnigString(onigLineText);
return {
lineLength,
lineTokens,
ruleStack: r.stack,
stoppedEarly: r.stoppedEarly
};
}
};
function initGrammar(grammar, base) {
grammar = clone(grammar);
grammar.repository = grammar.repository || {};
grammar.repository.$self = {
$vscodeTextmateLocation: grammar.$vscodeTextmateLocation,
patterns: grammar.patterns,
name: grammar.scopeName
};
grammar.repository.$base = base || grammar.repository.$self;
return grammar;
}
var AttributedScopeStack = class _AttributedScopeStack {
/**
* Invariant:
* ```
* if (parent && !scopePath.extends(parent.scopePath)) {
* throw new Error();
* }
* ```
*/
constructor(parent, scopePath, tokenAttributes) {
this.parent = parent;
this.scopePath = scopePath;
this.tokenAttributes = tokenAttributes;
}
static fromExtension(namesScopeList, contentNameScopesList) {
let current = namesScopeList;
let scopeNames = namesScopeList?.scopePath ?? null;
for (const frame of contentNameScopesList) {
scopeNames = ScopeStack.push(scopeNames, frame.scopeNames);
current = new _AttributedScopeStack(current, scopeNames, frame.encodedTokenAttributes);
}
return current;
}
static createRoot(scopeName, tokenAttributes) {
return new _AttributedScopeStack(null, new ScopeStack(null, scopeName), tokenAttributes);
}
static createRootAndLookUpScopeName(scopeName, tokenAttributes, grammar) {
const rawRootMetadata = grammar.getMetadataForScope(scopeName);
const scopePath = new ScopeStack(null, scopeName);
const rootStyle = grammar.themeProvider.themeMatch(scopePath);
const resolvedTokenAttributes = _AttributedScopeStack.mergeAttributes(
tokenAttributes,
rawRootMetadata,
rootStyle
);
return new _AttributedScopeStack(null, scopePath, resolvedTokenAttributes);
}
get scopeName() {
return this.scopePath.scopeName;
}
toString() {
return this.getScopeNames().join(" ");
}
equals(other) {
return _AttributedScopeStack.equals(this, other);
}
static equals(a, b) {
do {
if (a === b) {
return true;
}
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
if (a.scopeName !== b.scopeName || a.tokenAttributes !== b.tokenAttributes) {
return false;
}
a = a.parent;
b = b.parent;
} while (true);
}
static mergeAttributes(existingTokenAttributes, basicScopeAttributes, styleAttributes) {
let fontStyle = -1 /* NotSet */;
let foreground = 0;
let background = 0;
if (styleAttributes !== null) {
fontStyle = styleAttributes.fontStyle;
foreground = styleAttributes.foregroundId;
background = styleAttributes.backgroundId;
}
return EncodedTokenMetadata.set(
existingTokenAttributes,
basicScopeAttributes.languageId,
basicScopeAttributes.tokenType,
null,
fontStyle,
foreground,
background
);
}
pushAttributed(scopePath, grammar) {
if (scopePath === null) {
return this;
}
if (scopePath.indexOf(" ") === -1) {
return _AttributedScopeStack._pushAttributed(this, scopePath, grammar);
}
const scopes = scopePath.split(/ /g);
let result = this;
for (const scope of scopes) {
result = _AttributedScopeStack._pushAttributed(result, scope, grammar);
}
return result;
}
static _pushAttributed(target, scopeName, grammar) {
const rawMetadata = grammar.getMetadataForScope(scopeName);
const newPath = target.scopePath.push(scopeName);
const scopeThemeMatchResult = grammar.themeProvider.themeMatch(newPath);
const metadata = _AttributedScopeStack.mergeAttributes(
target.tokenAttributes,
rawMetadata,
scopeThemeMatchResult
);
return new _AttributedScopeStack(target, newPath, metadata);
}
getScopeNames() {
return this.scopePath.getSegments();
}
getExtensionIfDefined(base) {
const result = [];
let self = this;
while (self && self !== base) {
result.push({
encodedTokenAttributes: self.tokenAttributes,
scopeNames: self.scopePath.getExtensionIfDefined(self.parent?.scopePath ?? null)
});
self = self.parent;
}
return self === base ? result.reverse() : void 0;
}
};
var StateStackImpl = class _StateStackImpl {
/**
* Invariant:
* ```
* if (contentNameScopesList !== nameScopesList && contentNameScopesList?.parent !== nameScopesList) {
* throw new Error();
* }
* if (this.parent && !nameScopesList.extends(this.parent.contentNameScopesList)) {
* throw new Error();
* }
* ```
*/
constructor(parent, ruleId, enterPos, anchorPos, beginRuleCapturedEOL, endRule, nameScopesList, contentNameScopesList) {
this.parent = parent;
this.ruleId = ruleId;
this.beginRuleCapturedEOL = beginRuleCapturedEOL;
this.endRule = endRule;
this.nameScopesList = nameScopesList;
this.contentNameScopesList = contentNameScopesList;
this.depth = this.parent ? this.parent.depth + 1 : 1;
this._enterPos = enterPos;
this._anchorPos = anchorPos;
}
_stackElementBrand = void 0;
// TODO remove me
static NULL = new _StateStackImpl(
null,
0,
0,
0,
false,
null,
null,
null
);
/**
* The position on the current line where this state was pushed.
* This is relevant only while tokenizing a line, to detect endless loops.
* Its value is meaningless across lines.
*/
_enterPos;
/**
* The captured anchor position when this stack element was pushed.
* This is relevant only while tokenizing a line, to restore the anchor position when popping.
* Its value is meaningless across lines.
*/
_anchorPos;
/**
* The depth of the stack.
*/
depth;
equals(other) {
if (other === null) {
return false;
}
return _StateStackImpl._equals(this, other);
}
static _equals(a, b) {
if (a === b) {
return true;
}
if (!this._structuralEquals(a, b)) {
return false;
}
return AttributedScopeStack.equals(a.contentNameScopesList, b.contentNameScopesList);
}
/**
* A structural equals check. Does not take into account `scopes`.
*/
static _structuralEquals(a, b) {
do {
if (a === b) {
return true;
}
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
if (a.depth !== b.depth || a.ruleId !== b.ruleId || a.endRule !== b.endRule) {
return false;
}
a = a.parent;
b = b.parent;
} while (true);
}
clone() {
return this;
}
static _reset(el) {
while (el) {
el._enterPos = -1;
el._anchorPos = -1;
el = el.parent;
}
}
reset() {
_StateStackImpl._reset(this);
}
pop() {
return this.parent;
}
safePop() {
if (this.parent) {
return this.parent;
}
return this;
}
push(ruleId, enterPos, anchorPos, beginRuleCapturedEOL, endRule, nameScopesList, contentNameScopesList) {
return new _StateStackImpl(
this,
ruleId,
enterPos,
anchorPos,
beginRuleCapturedEOL,
endRule,
nameScopesList,
contentNameScopesList
);
}
getEnterPos() {
return this._enterPos;
}
getAnchorPos() {
return this._anchorPos;
}
getRule(grammar) {
return grammar.getRule(this.ruleId);
}
toString() {
const r = [];
this._writeString(r, 0);
return "[" + r.join(",") + "]";
}
_writeString(res, outIndex) {
if (this.parent) {
outIndex = this.parent._writeString(res, outIndex);
}
res[outIndex++] = `(${this.ruleId}, ${this.nameScopesList?.toString()}, ${this.contentNameScopesList?.toString()})`;
return outIndex;
}
withContentNameScopesList(contentNameScopeStack) {
if (this.contentNameScopesList === contentNameScopeStack) {
return this;
}
return this.parent.push(
this.ruleId,
this._enterPos,
this._anchorPos,
this.beginRuleCapturedEOL,
this.endRule,
this.nameScopesList,
contentNameScopeStack
);
}
withEndRule(endRule) {
if (this.endRule === endRule) {
return this;
}
return new _StateStackImpl(
this.parent,
this.ruleId,
this._enterPos,
this._anchorPos,
this.beginRuleCapturedEOL,
endRule,
this.nameScopesList,
this.contentNameScopesList
);
}
// Used to warn of endless loops
hasSameRuleAs(other) {
let el = this;
while (el && el._enterPos === other._enterPos) {
if (el.ruleId === other.ruleId) {
return true;
}
el = el.parent;
}
return false;
}
toStateStackFrame() {
return {
ruleId: ruleIdToNumber(this.ruleId),
beginRuleCapturedEOL: this.beginRuleCapturedEOL,
endRule: this.endRule,
nameScopesList: this.nameScopesList?.getExtensionIfDefined(this.parent?.nameScopesList ?? null) ?? [],
contentNameScopesList: this.contentNameScopesList?.getExtensionIfDefined(this.nameScopesList) ?? []
};
}
static pushFrame(self, frame) {
const namesScopeList = AttributedScopeStack.fromExtension(self?.nameScopesList ?? null, frame.nameScopesList);
return new _StateStackImpl(
self,
ruleIdFromNumber(frame.ruleId),
frame.enterPos ?? -1,
frame.anchorPos ?? -1,
frame.beginRuleCapturedEOL,
frame.endRule,
namesScopeList,
AttributedScopeStack.fromExtension(namesScopeList, frame.contentNameScopesList)
);
}
};
var BalancedBracketSelectors = class {
balancedBracketScopes;
unbalancedBracketScopes;
allowAny = false;
constructor(balancedBracketScopes, unbalancedBracketScopes) {
this.balancedBracketScopes = balancedBracketScopes.flatMap(
(selector) => {
if (selector === "*") {
this.allowAny = true;
return [];
}
return createMatchers(selector, nameMatcher).map((m) => m.matcher);
}
);
this.unbalancedBracketScopes = unbalancedBracketScopes.flatMap(
(selector) => createMatchers(selector, nameMatcher).map((m) => m.matcher)
);
}
get matchesAlways() {
return this.allowAny && this.unbalancedBracketScopes.length === 0;
}
get matchesNever() {
return this.balancedBracketScopes.length === 0 && !this.allowAny;
}
match(scopes) {
for (const excluder of this.unbalancedBracketScopes) {
if (excluder(scopes)) {
return false;
}
}
for (const includer of this.balancedBracketScopes) {
if (includer(scopes)) {
return true;
}
}
return this.allowAny;
}
};
var LineTokens = class {
constructor(emitBinaryTokens, lineText, tokenTypeOverrides, balancedBracketSelectors) {
this.balancedBracketSelectors = balancedBracketSelectors;
this._emitBinaryTokens = emitBinaryTokens;
this._tokenTypeOverrides = tokenTypeOverrides;
if (false) {
this._lineText = lineText;
} else {
this._lineText = null;
}
this._tokens = [];
this._binaryTokens = [];
this._lastTokenEndIndex = 0;
}
_emitBinaryTokens;
/**
* defined only if `false`.
*/
_lineText;
/**
* used only if `_emitBinaryTokens` is false.
*/
_tokens;
/**
* used only if `_emitBinaryTokens` is true.
*/
_binaryTokens;
_lastTokenEndIndex;
_tokenTypeOverrides;
produce(stack, endIndex) {
this.produceFromScopes(stack.contentNameScopesList, endIndex);
}
produceFromScopes(scopesList, endIndex) {
if (this._lastTokenEndIndex >= endIndex) {
return;
}
if (this._emitBinaryTokens) {
let metadata = scopesList?.tokenAttributes ?? 0;
let containsBalancedBrackets = false;
if (this.balancedBracketSelectors?.matchesAlways) {
containsBalancedBrackets = true;
}
if (this._tokenTypeOverrides.length > 0 || this.balancedBracketSelectors && !this.balancedBracketSelectors.matchesAlways && !this.balancedBracketSelectors.matchesNever) {
const scopes2 = scopesList?.getScopeNames() ?? [];
for (const tokenType of this._tokenTypeOverrides) {
if (tokenType.matcher(scopes2)) {
metadata = EncodedTokenMetadata.set(
metadata,
0,
toOptionalTokenType(tokenType.type),
null,
-1 /* NotSet */,
0,
0
);
}
}
if (this.balancedBracketSelectors) {
containsBalancedBrackets = this.balancedBracketSelectors.match(scopes2);
}
}
if (containsBalancedBrackets) {
metadata = EncodedTokenMetadata.set(
metadata,
0,
8 /* NotSet */,
containsBalancedBrackets,
-1 /* NotSet */,
0,
0
);
}
if (this._binaryTokens.length > 0 && this._binaryTokens[this._binaryTokens.length - 1] === metadata) {
this._lastTokenEndIndex = endIndex;
return;
}
this._binaryTokens.push(this._lastTokenEndIndex);
this._binaryTokens.push(metadata);
this._lastTokenEndIndex = endIndex;
return;
}
const scopes = scopesList?.getScopeNames() ?? [];
this._tokens.push({
startIndex: this._lastTokenEndIndex,
endIndex,
// value: lineText.substring(lastTokenEndIndex, endIndex),
scopes
});
this._lastTokenEndIndex = endIndex;
}
getResult(stack, lineLength) {
if (this._tokens.length > 0 && this._tokens[this._tokens.length - 1].startIndex === lineLength - 1) {
this._tokens.pop();
}
if (this._tokens.length === 0) {
this._lastTokenEndIndex = -1;
this.produce(stack, lineLength);
this._tokens[this._tokens.length - 1].startIndex = 0;
}
return this._tokens;
}
getBinaryResult(stack, lineLength) {
if (this._binaryTokens.length > 0 && this._binaryTokens[this._binaryTokens.length - 2] === lineLength - 1) {
this._binaryTokens.pop();
this._binaryTokens.pop();
}
if (this._binaryTokens.length === 0) {
this._lastTokenEndIndex = -1;
this.produce(stack, lineLength);
this._binaryTokens[this._binaryTokens.length - 2] = 0;
}
const result = new Uint32Array(this._binaryTokens.length);
for (let i = 0, len = this._binaryTokens.length; i < len; i++) {
result[i] = this._binaryTokens[i];
}
return result;
}
};
// src/registry.ts
var SyncRegistry = class {
constructor(theme, _onigLib) {
this._onigLib = _onigLib;
this._theme = theme;
}
_grammars = /* @__PURE__ */ new Map();
_rawGrammars = /* @__PURE__ */ new Map();
_injectionGrammars = /* @__PURE__ */ new Map();
_theme;
dispose() {
for (const grammar of this._grammars.values()) {
grammar.dispose();
}
}
setTheme(theme) {
this._theme = theme;
}
getColorMap() {
return this._theme.getColorMap();
}
/**
* Add `grammar` to registry and return a list of referenced scope names
*/
addGrammar(grammar, injectionScopeNames) {
this._rawGrammars.set(grammar.scopeName, grammar);
if (injectionScopeNames) {
this._injectionGrammars.set(grammar.scopeName, injectionScopeNames);
}
}
/**
* Lookup a raw grammar.
*/
lookup(scopeName) {
return this._rawGrammars.get(scopeName);
}
/**
* Returns the injections for the given grammar
*/
injections(targetScope) {
return this._injectionGrammars.get(targetScope);
}
/**
* Get the default theme settings
*/
getDefaults() {
return this._theme.getDefaults();
}
/**
* Match a scope in the theme.
*/
themeMatch(scopePath) {
return this._theme.match(scopePath);
}
/**
* Lookup a grammar.
*/
grammarForScopeName(scopeName, initialLanguage, embeddedLanguages, tokenTypes, balancedBracketSelectors) {
if (!this._grammars.has(scopeName)) {
let rawGrammar = this._rawGrammars.get(scopeName);
if (!rawGrammar) {
return null;
}
this._grammars.set(scopeName, createGrammar(
scopeName,
rawGrammar,
initialLanguage,
embeddedLanguages,
tokenTypes,
balancedBracketSelectors,
this,
this._onigLib
));
}
return this._grammars.get(scopeName);
}
};
// src/index.ts
var Registry = class {
_options;
_syncRegistry;
_ensureGrammarCache;
constructor(options) {
this._options = options;
this._syncRegistry = new SyncRegistry(
Theme.createFromRawTheme(options.theme, options.colorMap),
options.onigLib
);
this._ensureGrammarCache = /* @__PURE__ */ new Map();
}
dispose() {
this._syncRegistry.dispose();
}
/**
* Change the theme. Once called, no previous `ruleStack` should be used anymore.
*/
setTheme(theme, colorMap) {
this._syncRegistry.setTheme(Theme.createFromRawTheme(theme, colorMap));
}
/**
* Returns a lookup array for color ids.
*/
getColorMap() {
return this._syncRegistry.getColorMap();
}
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
* Please do not use language id 0.
*/
loadGrammarWithEmbeddedLanguages(initialScopeName, initialLanguage, embeddedLanguages) {
return this.loadGrammarWithConfiguration(initialScopeName, initialLanguage, { embeddedLanguages });
}
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
* Please do not use language id 0.
*/
loadGrammarWithConfiguration(initialScopeName, initialLanguage, configuration) {
return this._loadGrammar(
initialScopeName,
initialLanguage,
configuration.embeddedLanguages,
configuration.tokenTypes,
new BalancedBracketSelectors(
configuration.balancedBracketSelectors || [],
configuration.unbalancedBracketSelectors || []
)
);
}
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
*/
loadGrammar(initialScopeName) {
return this._loadGrammar(initialScopeName, 0, null, null, null);
}
_loadGrammar(initialScopeName, initialLanguage, embeddedLanguages, tokenTypes, balancedBracketSelectors) {
const dependencyProcessor = new ScopeDependencyProcessor(this._syncRegistry, initialScopeName);
while (dependencyProcessor.Q.length > 0) {
dependencyProcessor.Q.map((request) => this._loadSingleGrammar(request.scopeName));
dependencyProcessor.processQueue();
}
return this._grammarForScopeName(
initialScopeName,
initialLanguage,
embeddedLanguages,
tokenTypes,
balancedBracketSelectors
);
}
_loadSingleGrammar(scopeName) {
if (!this._ensureGrammarCache.has(scopeName)) {
this._doLoadSingleGrammar(scopeName);
this._ensureGrammarCache.set(scopeName, true);
}
}
_doLoadSingleGrammar(scopeName) {
const grammar = this._options.loadGrammar(scopeName);
if (grammar) {
const injections = typeof this._options.getInjections === "function" ? this._options.getInjections(scopeName) : void 0;
this._syncRegistry.addGrammar(grammar, injections);
}
}
/**
* Adds a rawGrammar.
*/
addGrammar(rawGrammar, injections = [], initialLanguage = 0, embeddedLanguages = null) {
this._syncRegistry.addGrammar(rawGrammar, injections);
return this._grammarForScopeName(rawGrammar.scopeName, initialLanguage, embeddedLanguages);
}
/**
* Get the grammar for `scopeName`. The grammar must first be created via `loadGrammar` or `addGrammar`.
*/
_grammarForScopeName(scopeName, initialLanguage = 0, embeddedLanguages = null, tokenTypes = null, balancedBracketSelectors = null) {
return this._syncRegistry.grammarForScopeName(
scopeName,
initialLanguage,
embeddedLanguages,
tokenTypes,
balancedBracketSelectors
);
}
};
var INITIAL = StateStackImpl.NULL;
export {
EncodedTokenMetadata,
FindOption,
FontStyle,
INITIAL,
Registry,
Theme,
disposeOnigString
};