feat: Add LaTeX markdown rendering as per MSC2191
This commit is contained in:
parent
090f0c326c
commit
be6824b746
|
@ -76,6 +76,51 @@ class EmoteSyntax extends InlineSyntax {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InlineLatexSyntax extends InlineSyntax {
|
||||||
|
InlineLatexSyntax() : super(r'(?<=\s|^)\$(?=\S)([^\n$]+)(?<=\S)\$(?=\s|$)');
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool onMatch(InlineParser parser, Match match) {
|
||||||
|
final latex = htmlEscape.convert(match[1]);
|
||||||
|
final element = Element('span', [Element.text('code', latex)]);
|
||||||
|
element.attributes['data-mx-maths'] = latex;
|
||||||
|
parser.addNode(element);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BlockLatexSyntax extends BlockSyntax {
|
||||||
|
@override
|
||||||
|
RegExp get pattern => RegExp(r'^[ ]{0,3}\${2}\s*$');
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> parseChildLines(BlockParser parser) {
|
||||||
|
var childLines = <String>[];
|
||||||
|
parser.advance();
|
||||||
|
while (!parser.isDone) {
|
||||||
|
if (!pattern.hasMatch(parser.current)) {
|
||||||
|
childLines.add(parser.current);
|
||||||
|
parser.advance();
|
||||||
|
} else {
|
||||||
|
parser.advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return childLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Node parse(BlockParser parser) {
|
||||||
|
final childLines = parseChildLines(parser);
|
||||||
|
final latex = htmlEscape.convert(childLines.join('\n'));
|
||||||
|
final element = Element('div', [
|
||||||
|
Element('pre', [Element.text('code', latex)])
|
||||||
|
]);
|
||||||
|
element.attributes['data-mx-maths'] = latex;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PillSyntax extends InlineSyntax {
|
class PillSyntax extends InlineSyntax {
|
||||||
PillSyntax() : super(r'([@#!][^\s:]*:[^\s]+\.\w+)');
|
PillSyntax() : super(r'([@#!][^\s:]*:[^\s]+\.\w+)');
|
||||||
|
|
||||||
|
@ -94,18 +139,22 @@ String markdown(String text, [Map<String, Map<String, String>> emotePacks]) {
|
||||||
var ret = markdownToHtml(
|
var ret = markdownToHtml(
|
||||||
text,
|
text,
|
||||||
extensionSet: ExtensionSet.commonMark,
|
extensionSet: ExtensionSet.commonMark,
|
||||||
|
blockSyntaxes: [
|
||||||
|
BlockLatexSyntax(),
|
||||||
|
],
|
||||||
inlineSyntaxes: [
|
inlineSyntaxes: [
|
||||||
StrikethroughSyntax(),
|
StrikethroughSyntax(),
|
||||||
LinebreakSyntax(),
|
LinebreakSyntax(),
|
||||||
SpoilerSyntax(),
|
SpoilerSyntax(),
|
||||||
EmoteSyntax(emotePacks),
|
EmoteSyntax(emotePacks),
|
||||||
PillSyntax()
|
PillSyntax(),
|
||||||
|
InlineLatexSyntax(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
var stripPTags = '<p>'.allMatches(ret).length <= 1;
|
var stripPTags = '<p>'.allMatches(ret).length <= 1;
|
||||||
if (stripPTags) {
|
if (stripPTags) {
|
||||||
final otherBlockTags = [
|
const otherBlockTags = {
|
||||||
'table',
|
'table',
|
||||||
'pre',
|
'pre',
|
||||||
'ol',
|
'ol',
|
||||||
|
@ -116,8 +165,9 @@ String markdown(String text, [Map<String, Map<String, String>> emotePacks]) {
|
||||||
'h4',
|
'h4',
|
||||||
'h5',
|
'h5',
|
||||||
'h6',
|
'h6',
|
||||||
'blockquote'
|
'blockquote',
|
||||||
];
|
'div',
|
||||||
|
};
|
||||||
for (final tag in otherBlockTags) {
|
for (final tag in otherBlockTags) {
|
||||||
// we check for the close tag as the opening one might have attributes
|
// we check for the close tag as the opening one might have attributes
|
||||||
if (ret.contains('</${tag}>')) {
|
if (ret.contains('</${tag}>')) {
|
||||||
|
|
|
@ -70,5 +70,11 @@ void main() {
|
||||||
expect(markdown('!blah:example.org'),
|
expect(markdown('!blah:example.org'),
|
||||||
'<a href="https://matrix.to/#/!blah:example.org">!blah:example.org</a>');
|
'<a href="https://matrix.to/#/!blah:example.org">!blah:example.org</a>');
|
||||||
});
|
});
|
||||||
|
test('latex', () {
|
||||||
|
expect(markdown('meep \$\\frac{2}{3}\$'),
|
||||||
|
'meep <span data-mx-maths="\\frac{2}{3}"><code>\\frac{2}{3}</code></span>');
|
||||||
|
expect(markdown('hey\n\$\$\nbeep\nboop\n\$\$\nmeow'),
|
||||||
|
'<p>hey</p>\n<div data-mx-maths="beep\nboop">\n<pre><code>beep\nboop</code></pre>\n</div>\n<p>meow</p>');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue