Skip to content

Commit efab56e

Browse files
wip
1 parent 4233989 commit efab56e

File tree

5 files changed

+1051
-126
lines changed

5 files changed

+1051
-126
lines changed

lib/model/content.dart

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import 'package:collection/collection.dart';
22
import 'package:flutter/foundation.dart';
3+
import 'package:flutter/widgets.dart';
34
import 'package:html/dom.dart' as dom;
45
import 'package:html/parser.dart';
56

67
import '../api/model/model.dart';
78
import '../api/model/submessage.dart';
89
import 'code_block.dart';
10+
import 'katex.dart';
911

1012
/// A node in a parse tree for Zulip message-style content.
1113
///
@@ -340,23 +342,46 @@ class CodeBlockSpanNode extends ContentNode {
340342
}
341343
}
342344

343-
class MathBlockNode extends BlockContentNode {
344-
const MathBlockNode({super.debugHtmlNode, required this.texSource});
345+
class KatexSpan extends ContentNode {
346+
const KatexSpan({
347+
required this.spanClasses,
348+
required this.spanStyle,
349+
required this.text,
350+
this.spans = const [],
351+
});
345352

346-
final String texSource;
353+
final List<String> spanClasses;
354+
final KatexSpanStyle? spanStyle;
355+
final String? text;
356+
final List<KatexSpan> spans;
347357

348358
@override
349-
bool operator ==(Object other) {
350-
return other is MathBlockNode && other.texSource == texSource;
359+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
360+
super.debugFillProperties(properties);
361+
properties.add(StringProperty('spanClass', spanClasses.join(', ')));
362+
properties.add(KatexSpanStyleProperty('spanStyle', spanStyle));
363+
properties.add(StringProperty('text', text));
351364
}
352365

353366
@override
354-
int get hashCode => Object.hash('MathBlockNode', texSource);
367+
List<DiagnosticsNode> debugDescribeChildren() {
368+
return spans.map((node) => node.toDiagnosticsNode()).toList();
369+
}
370+
}
371+
372+
class MathBlockNode extends BlockContentNode {
373+
const MathBlockNode({
374+
super.debugHtmlNode,
375+
required this.texSource,
376+
required this.spans,
377+
});
378+
379+
final String texSource;
380+
final List<KatexSpan> spans;
355381

356382
@override
357-
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
358-
super.debugFillProperties(properties);
359-
properties.add(StringProperty('texSource', texSource));
383+
List<DiagnosticsNode> debugDescribeChildren() {
384+
return spans.map((node) => node.toDiagnosticsNode()).toList();
360385
}
361386
}
362387

@@ -1113,6 +1138,13 @@ class _ZulipContentParser {
11131138
return inlineParser.parseBlockInline(nodes);
11141139
}
11151140

1141+
// BlockContentNode parseMathBlock(dom.Element element) {
1142+
// final debugHtmlNode = kDebugMode ? element : null;
1143+
// final texSource = _parseMath(element, block: true);
1144+
// if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
1145+
// return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1146+
// }
1147+
11161148
BlockContentNode parseListNode(dom.Element element) {
11171149
assert(element.localName == 'ol' || element.localName == 'ul');
11181150
assert(element.className.isEmpty);
@@ -1624,11 +1656,9 @@ class _ZulipContentParser {
16241656
})());
16251657

16261658
final firstChild = nodes.first as dom.Element;
1627-
final texSource = _parseMath(firstChild, block: true);
1628-
if (texSource != null) {
1629-
result.add(MathBlockNode(
1630-
texSource: texSource,
1631-
debugHtmlNode: kDebugMode ? firstChild : null));
1659+
final block = parseKatexBlock(firstChild);
1660+
if (block != null) {
1661+
result.add(block);
16321662
} else {
16331663
result.add(UnimplementedBlockContentNode(htmlNode: firstChild));
16341664
}
@@ -1649,7 +1679,6 @@ class _ZulipContentParser {
16491679
: nodes.length;
16501680
for (int i = 1; i < length; i++) {
16511681
final child = nodes[i];
1652-
final debugHtmlNode = kDebugMode ? child : null;
16531682

16541683
// If there are multiple <span class="katex-display"> nodes in a <p>
16551684
// each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
@@ -1659,11 +1688,9 @@ class _ZulipContentParser {
16591688
if (child case dom.Text(text: '\n\n')) continue;
16601689

16611690
if (child case dom.Element(localName: 'span', className: 'katex-display')) {
1662-
final texSource = _parseMath(child, block: true);
1663-
if (texSource != null) {
1664-
result.add(MathBlockNode(
1665-
texSource: texSource,
1666-
debugHtmlNode: debugHtmlNode));
1691+
final block = parseKatexBlock(firstChild);
1692+
if (block != null) {
1693+
result.add(block);
16671694
continue;
16681695
}
16691696
}
@@ -1672,6 +1699,33 @@ class _ZulipContentParser {
16721699
}
16731700
}
16741701

1702+
BlockContentNode? parseKatexBlock(dom.Element element) {
1703+
assert(element.localName == 'span' && element.className == 'katex-display');
1704+
if (element.nodes.length != 1) return null;
1705+
final child = element.nodes.single;
1706+
if (child is! dom.Element) return null;
1707+
if (child.localName != 'span') return null;
1708+
if (child.className != 'katex') return null;
1709+
1710+
if (child.nodes.length != 2) return null;
1711+
final grandchild = child.nodes.last;
1712+
if (grandchild is! dom.Element) return null;
1713+
if (grandchild.localName != 'span') return null;
1714+
if (grandchild.className != 'katex-html') return null;
1715+
1716+
try {
1717+
final debugHtmlNode = kDebugMode ? element : null;
1718+
final spans = parseKatexSpans(grandchild);
1719+
return MathBlockNode(
1720+
texSource: '',
1721+
spans: spans,
1722+
debugHtmlNode: debugHtmlNode);
1723+
} on KatexHtmlParseError catch (e, st) {
1724+
print('$e\n$st');
1725+
return null;
1726+
}
1727+
}
1728+
16751729
BlockContentNode parseBlockContent(dom.Node node) {
16761730
final debugHtmlNode = kDebugMode ? node : null;
16771731
if (node is! dom.Element) {

0 commit comments

Comments
 (0)