cm-tarnation
Version:
An alternative parser for CodeMirror 6
75 lines • 3.62 kB
JavaScript
/* 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