/
githubmirror
/
atom
Обзор
Документация
Войти
/
githubmirror
/
atom
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/tree-sitter-grammar.js
194 строки
5 KB
Ethan Johnson
pass node
26 ноя 2019, 22:09
26 ноя 2019, 22:09
88ad0b1
Код
Авторство
О чём код?
const path = require('path'); const SyntaxScopeMap = require('./syntax-scope-map'); const Module = require('module'); module.exports = class TreeSitterGrammar { constructor(registry, filePath, params) { this.registry = registry; this.name = params.name; this.scopeName = params.scopeName; // TODO - Remove the `RegExp` spelling and only support `Regex`, once all of the existing // Tree-sitter grammars are updated to spell it `Regex`. this.contentRegex = buildRegex(params.contentRegex || params.contentRegExp); this.injectionRegex = buildRegex( params.injectionRegex || params.injectionRegExp ); this.firstLineRegex = buildRegex(params.firstLineRegex); this.folds = params.folds || []; this.folds.forEach(normalizeFoldSpecification); this.commentStrings = { commentStartString: params.comments && params.comments.start, commentEndString: params.comments && params.comments.end }; const scopeSelectors = {}; for (const key in params.scopes || {}) { const classes = preprocessScopes(params.scopes[key]); const selectors = key.split(/,\s+/); for (let selector of selectors) { selector = selector.trim(); if (!selector) continue; if (scopeSelectors[selector]) { scopeSelectors[selector] = [].concat( scopeSelectors[selector], classes ); } else { scopeSelectors[selector] = classes; } } } this.scopeMap = new SyntaxScopeMap(scopeSelectors); this.fileTypes = params.fileTypes || []; this.injectionPointsByType = {}; for (const injectionPoint of params.injectionPoints || []) { this.addInjectionPoint(injectionPoint); } // TODO - When we upgrade to a new enough version of node, use `require.resolve` // with the new `paths` option instead of this private API. const languageModulePath = Module._resolveFilename(params.parser, { id: filePath, filename: filePath, paths: Module._nodeModulePaths(path.dirname(filePath)) }); this.languageModule = require(languageModulePath); this.classNamesById = new Map(); this.scopeNamesById = new Map(); this.idsByScope = Object.create(null); this.nextScopeId = 256 + 1; this.registration = null; } inspect() { return `TreeSitterGrammar {scopeName: ${this.scopeName}}`; } idForScope(scopeName) { if (!scopeName) { return undefined; } let id = this.idsByScope[scopeName]; if (!id) { id = this.nextScopeId += 2; const className = scopeName .split('.') .map(s => `syntax--${s}`) .join(' '); this.idsByScope[scopeName] = id; this.classNamesById.set(id, className); this.scopeNamesById.set(id, scopeName); } return id; } classNameForScopeId(id) { return this.classNamesById.get(id); } scopeNameForScopeId(id) { return this.scopeNamesById.get(id); } activate() { this.registration = this.registry.addGrammar(this); } deactivate() { if (this.registration) this.registration.dispose(); } addInjectionPoint(injectionPoint) { let injectionPoints = this.injectionPointsByType[injectionPoint.type]; if (!injectionPoints) { injectionPoints = this.injectionPointsByType[injectionPoint.type] = []; } injectionPoints.push(injectionPoint); } removeInjectionPoint(injectionPoint) { const injectionPoints = this.injectionPointsByType[injectionPoint.type]; if (injectionPoints) { const index = injectionPoints.indexOf(injectionPoint); if (index !== -1) injectionPoints.splice(index, 1); if (injectionPoints.length === 0) { delete this.injectionPointsByType[injectionPoint.type]; } } } /* Section - Backward compatibility shims */ onDidUpdate(callback) { // do nothing } tokenizeLines(text, compatibilityMode = true) { return text.split('\n').map(line => this.tokenizeLine(line, null, false)); } tokenizeLine(line, ruleStack, firstLine) { return { value: line, scopes: [this.scopeName] }; } }; const preprocessScopes = value => typeof value === 'string' ? value : Array.isArray(value) ? value.map(preprocessScopes) : value.match ? { match: new RegExp(value.match), scopes: preprocessScopes(value.scopes) } : Object.assign({}, value, { scopes: preprocessScopes(value.scopes) }); const NODE_NAME_REGEX = /[\w_]+/; function matcherForSpec(spec) { if (typeof spec === 'string') { if (spec[0] === '"' && spec[spec.length - 1] === '"') { return { type: spec.substr(1, spec.length - 2), named: false }; } if (!NODE_NAME_REGEX.test(spec)) { return { type: spec, named: false }; } return { type: spec, named: true }; } return spec; } function normalizeFoldSpecification(spec) { if (spec.type) { if (Array.isArray(spec.type)) { spec.matchers = spec.type.map(matcherForSpec); } else { spec.matchers = [matcherForSpec(spec.type)]; } } if (spec.start) normalizeFoldSpecification(spec.start); if (spec.end) normalizeFoldSpecification(spec.end); } function buildRegex(value) { // Allow multiple alternatives to be specified via an array, for // readability of the grammar file if (Array.isArray(value)) value = value.map(_ => `(${_})`).join('|'); if (typeof value === 'string') return new RegExp(value); return null; }