103 lines
3.9 KiB
TypeScript
103 lines
3.9 KiB
TypeScript
/**
|
|
* CodeMirror 6 language support for Decodal.
|
|
*
|
|
* This module exports the Decodal language extension, parser metadata, and the
|
|
* bundled highlight style used by the official Decodal playground. Add
|
|
* {@link decodal} to a CodeMirror extension set to enable highlighting,
|
|
* indentation, and folding for Decodal documents.
|
|
*
|
|
* @module
|
|
*/
|
|
import { HighlightStyle, LRLanguage, LanguageSupport, delimitedIndent, foldNodeProp, indentNodeProp, syntaxHighlighting } from 'npm:@codemirror/language@^6.12.4';
|
|
import { styleTags, tags as t } from 'npm:@lezer/highlight@^1.2.3';
|
|
import { parser } from './decodal-parser-jsr.js';
|
|
|
|
const parserWithMetadata = parser.configure({
|
|
props: [
|
|
styleTags({
|
|
'Let In Match Import Default As': t.keyword,
|
|
'True False': t.bool,
|
|
Identifier: t.variableName,
|
|
String: t.string,
|
|
Regex: t.regexp,
|
|
'Integer Float': t.number,
|
|
Comment: t.lineComment,
|
|
'Plus Minus Star Slash PlusPlus Ellipsis Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
|
|
'LBrace RBrace': t.brace,
|
|
'LBracket RBracket': t.squareBracket,
|
|
'LParen RParen': t.paren,
|
|
'Semicolon Comma Dot Colon': t.punctuation,
|
|
}),
|
|
indentNodeProp.add({
|
|
Object: delimitedIndent({ closing: '}', align: false }),
|
|
MapConstraint: delimitedIndent({ closing: '}', align: false }),
|
|
Array: delimitedIndent({ closing: ']', align: false }),
|
|
ArrayConstraint: delimitedIndent({ closing: ']', align: false }),
|
|
MatchExpression: delimitedIndent({ closing: '}', align: false }),
|
|
LetExpression: context => context.column(context.node.from) + context.unit,
|
|
}),
|
|
foldNodeProp.add({
|
|
Object: foldDelimited('{', '}'),
|
|
MapConstraint: foldDelimited('{', '}'),
|
|
Array: foldDelimited('[', ']'),
|
|
ArrayConstraint: foldDelimited('[', ']'),
|
|
MatchExpression: foldDelimited('{', '}'),
|
|
}),
|
|
],
|
|
});
|
|
|
|
function foldDelimited(open: string, close: string) {
|
|
return (node: { from: number; to: number }, state: { doc: { sliceString(from: number, to: number): string } }) => {
|
|
const text = state.doc.sliceString(node.from, node.to);
|
|
const openIndex = text.indexOf(open);
|
|
const closeIndex = text.lastIndexOf(close);
|
|
if (openIndex < 0 || closeIndex <= openIndex) return null;
|
|
const from = node.from + openIndex + open.length;
|
|
const to = node.from + closeIndex;
|
|
return from < to ? { from, to } : null;
|
|
};
|
|
}
|
|
|
|
/** Decodal LR language definition for CodeMirror 6. */
|
|
export const decodalLanguage: LRLanguage = LRLanguage.define({
|
|
parser: parserWithMetadata,
|
|
languageData: {
|
|
commentTokens: { line: '#' },
|
|
closeBrackets: { brackets: ['(', '[', '{', '"'] },
|
|
},
|
|
});
|
|
|
|
/** Default Decodal highlight style used by the playground. */
|
|
export const decodalHighlightStyle: HighlightStyle = HighlightStyle.define([
|
|
{ tag: t.keyword, color: '#93c5fd', fontWeight: '700' },
|
|
{ tag: t.variableName, color: 'inherit' },
|
|
{ tag: t.bool, color: '#fbbf24' },
|
|
{ tag: t.number, color: '#fbbf24' },
|
|
{ tag: t.string, color: '#86efac' },
|
|
{ tag: t.regexp, color: '#86efac' },
|
|
{ tag: t.lineComment, color: '#94a3b8', fontStyle: 'italic' },
|
|
{ tag: t.operator, color: '#f9a8d4' },
|
|
{ tag: [t.brace, t.squareBracket, t.paren, t.punctuation], color: '#f9a8d4' },
|
|
]);
|
|
|
|
/** Options for {@link decodal}. */
|
|
export interface DecodalOptions {
|
|
/** Include the bundled {@link decodalHighlightStyle}. Defaults to `true`. */
|
|
highlight?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Create CodeMirror language support for Decodal.
|
|
*
|
|
* @param options - Optional language support options.
|
|
* @returns A CodeMirror extension bundle containing the Decodal language and,
|
|
* unless disabled, the default highlight style.
|
|
*/
|
|
export function decodal(options: DecodalOptions = {}): LanguageSupport {
|
|
const { highlight = true } = options;
|
|
return new LanguageSupport(
|
|
decodalLanguage,
|
|
highlight ? [syntaxHighlighting(decodalHighlightStyle)] : [],
|
|
);
|
|
}
|