UNPKG

cm-tarnation

Version:

An alternative parser for CodeMirror 6

75 lines 3.62 kB
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { defineLanguageFacet, Language, languageDataProp, LanguageDescription, LanguageSupport } from "@codemirror/language"; import { NodeProp, NodeSet, NodeType } from "@lezer/common"; import { Autocompleter } from "./completion/autcomplete"; import { NodeID, NODE_ERROR_ADVANCE, NODE_ERROR_INCOMPLETE } from "./constants"; import { Grammar } from "./grammar/grammar"; import { ParserFactory } from "./parser"; import { removeUndefined } from "./util"; /** * Tarnation language. Use the `load` method to get the extension needed to * load the language into CodeMirror. If you need a `LanguageDescription`, * the `description` property will hold one. */ export class TarnationLanguage { /** Will be true if the langauge has been loaded once. */ loaded = false; /** Will be set to the number of milliseconds the last parse time took. */ performance = 0; constructor({ name, grammar, nestLanguages = [], configure = {}, alias, extensions, languageData = {}, supportExtensions = [] }) { const dataDescription = removeUndefined({ name, alias, extensions }); this.languageData = { ...dataDescription, ...languageData }; this.nestLanguages = nestLanguages; this.grammarData = grammar; this.configure = configure; this.extensions = supportExtensions; this.description = LanguageDescription.of({ ...dataDescription, load: async () => this.load() }); } /** * Loads and processes the language. Calling this function repeatedly * will just return the previously loaded language. */ load() { // setup grammar data if (this.description?.support) return this.description.support; const def = typeof this.grammarData === "function" ? this.grammarData() : this.grammarData; this.grammar = new Grammar(def, this.configure.variables); // merge data from the grammar Object.assign(this.languageData, this.grammar.data); // setup node data this.stateProp = new NodeProp({ perNode: true }); const facet = defineLanguageFacet(this.languageData); this.topNode = NodeType.define({ id: NodeID.TOP, name: this.description.name, top: true, props: [[languageDataProp, facet]] }); const nodeTypes = this.grammar.repository.nodes().map(n => n.type); // unshift our special nodes into the list // (NodeType.none always has an ID of 0) nodeTypes.unshift(NodeType.none, this.topNode, NODE_ERROR_ADVANCE, NODE_ERROR_INCOMPLETE); let nodeSet = new NodeSet(nodeTypes); if (this.configure.props) nodeSet = nodeSet.extend(...this.configure.props); this.nodeTypes = nodeTypes; this.nodeSet = nodeSet; if (this.configure.autocomplete) { this.autocompleter = new Autocompleter(this); this.languageData.autocomplete = this.autocompleter.handle.bind(this.autocompleter); } // setup language support this.language = new Language(facet, new ParserFactory(this)); this.support = new LanguageSupport(this.language, this.extensions); this.loaded = true; console.log(this); return this.support; } } //# sourceMappingURL=language.js.map