obsidian-visualiser/shared/grammar/callout.extension.ts

58 lines
2.0 KiB
TypeScript

import type { MarkdownConfig } from '@lezer/markdown';
import { styleTags, tags } from '@lezer/highlight';
export const callout: MarkdownConfig = {
defineNodes: [
'CalloutBlock',
'CalloutMarker',
'CalloutMark',
'CalloutType',
'CalloutTitle',
'CalloutLine',
'CalloutContent',
],
parseBlock: [{
name: 'Callout',
before: 'Blockquote',
parse(cx, line) {
const match = /^>\s*\[!(\w+)\](?:\s+(.*))?/.exec(line.text);
if (!match || !match[1]) return false; //No match
const start = cx.lineStart, children = [];
const quoteEnd = start + line.text.indexOf('[!');
const typeStart = quoteEnd + 2;
const typeEnd = typeStart + match[1].length;
const bracketEnd = typeEnd + 1;
children.push(cx.elt('CalloutMarker', start, bracketEnd, [ cx.elt('CalloutMark', start, quoteEnd), cx.elt('CalloutType', typeStart, typeEnd) ]));
if(match[2]) children.push(cx.elt('CalloutTitle', bracketEnd + 1, start + line.text.length));
while (cx.nextLine() && line.text.startsWith('>'))
{
const pos = line.text.substring(1).search(/\S/) + 1;
children.push(cx.elt('CalloutLine', cx.lineStart, cx.lineStart + line.text.length, [
cx.elt('CalloutMark', cx.lineStart, cx.lineStart + pos),
cx.elt('CalloutContent', cx.lineStart + pos, cx.lineStart + line.text.length),
]))
}
cx.addElement(cx.elt('CalloutBlock', start, cx.lineStart - 1, children));
return true;
}
}],
props: [
styleTags({
'CalloutBlock': tags.special(tags.quote),
'CalloutMarker': tags.meta,
'CalloutMark': tags.meta,
'CalloutType': tags.keyword,
'CalloutTitle': tags.heading,
'CalloutLine': tags.content,
'CalloutContent': tags.content,
})
]
};