|
|
@@ -0,0 +1,57 @@
|
|
|
+import { InlineContext, MarkdownConfig, InlineParser } from '@lezer/markdown'
|
|
|
+
|
|
|
+const DOLLAR = 36 /* '$' */
|
|
|
+
|
|
|
+// Whitespace (including the start/end of the inline section, where `char`
|
|
|
+// returns -1).
|
|
|
+const isSpace = (code: number) =>
|
|
|
+ code === -1 || code === 32 || code === 9 || code === 10 || code === 13
|
|
|
+
|
|
|
+const isDigit = (code: number) => code >= 48 && code <= 57
|
|
|
+
|
|
|
+const InlineMathDelim = { resolve: 'InlineMath', mark: 'InlineMathMark' }
|
|
|
+const BlockMathDelim = { resolve: 'BlockMath', mark: 'BlockMathMark' }
|
|
|
+
|
|
|
+// Inline parsing runs over the whole paragraph, so `$$…$$` handles multi-line
|
|
|
+// equations as long as there is no blank line inside them.
|
|
|
+const blockMathParser: InlineParser = {
|
|
|
+ name: 'BlockMath',
|
|
|
+ parse(cx: InlineContext, next: number, pos: number) {
|
|
|
+ if (next !== DOLLAR || cx.char(pos + 1) !== DOLLAR) {
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ return cx.addDelimiter(BlockMathDelim, pos, pos + 2, true, true)
|
|
|
+ },
|
|
|
+ // Run before the default `Emphasis` parser, and (via `InlineMath`'s `after`)
|
|
|
+ // before the single-dollar inline parser, so `$$` is matched as a display
|
|
|
+ // delimiter rather than two empty inline ones.
|
|
|
+ before: 'Emphasis',
|
|
|
+}
|
|
|
+
|
|
|
+const inlineMathParser: InlineParser = {
|
|
|
+ name: 'InlineMath',
|
|
|
+ parse(cx: InlineContext, next: number, pos: number) {
|
|
|
+ if (next !== DOLLAR) {
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ const before = cx.char(pos - 1)
|
|
|
+ const after = cx.char(pos + 1)
|
|
|
+ const canOpen = !isSpace(after)
|
|
|
+ const canClose = !isSpace(before) && !isDigit(after)
|
|
|
+ if (!canOpen && !canClose) {
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ return cx.addDelimiter(InlineMathDelim, pos, pos + 1, canOpen, canClose)
|
|
|
+ },
|
|
|
+ // Run after `BlockMath` so `$$` is tried as a display delimiter first, but
|
|
|
+ // still before `Emphasis`. The default `Escape` parser consumes `\$` first.
|
|
|
+ after: 'BlockMath',
|
|
|
+}
|
|
|
+
|
|
|
+export const Math: MarkdownConfig = {
|
|
|
+ // No `style` is set on these nodes: math is rendered by the visual editor
|
|
|
+ // (which slices the raw source), so the grammar change stays inert for
|
|
|
+ // source-mode syntax highlighting and non-experiment users.
|
|
|
+ defineNodes: ['InlineMath', 'InlineMathMark', 'BlockMath', 'BlockMathMark'],
|
|
|
+ parseInline: [blockMathParser, inlineMathParser],
|
|
|
+}
|