Extract CodeMirror language package

This commit is contained in:
2026-07-09 03:49:44 +09:00
parent 375bc80a57
commit e4b9247c45
19 changed files with 397 additions and 14 deletions
+77
View File
@@ -0,0 +1,77 @@
import { HighlightStyle, LRLanguage, LanguageSupport, 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': 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 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: context => context.column(context.node.from) + context.unit,
Array: context => context.column(context.node.from) + context.unit,
MatchExpression: context => context.column(context.node.from) + context.unit,
LetExpression: context => context.column(context.node.from) + context.unit,
}),
foldNodeProp.add({
Object: foldDelimited('{', '}'),
Array: 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;
};
}
export const decodalLanguage: LRLanguage = LRLanguage.define({
parser: parserWithMetadata,
languageData: {
commentTokens: { line: '#' },
closeBrackets: { brackets: ['(', '[', '{', '"'] },
},
});
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' },
]);
export interface DecodalOptions {
highlight?: boolean;
}
export function decodal(options: DecodalOptions = {}): LanguageSupport {
const { highlight = true } = options;
return new LanguageSupport(
decodalLanguage,
highlight ? [syntaxHighlighting(decodalHighlightStyle)] : [],
);
}