Skip to content

Commit 6cf134f

Browse files
wip
1 parent 61d30f6 commit 6cf134f

File tree

5 files changed

+979
-56
lines changed

5 files changed

+979
-56
lines changed

lib/model/content.dart

+75-24
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
///
@@ -334,23 +336,46 @@ class CodeBlockSpanNode extends ContentNode {
334336
}
335337
}
336338

337-
class MathBlockNode extends BlockContentNode {
338-
const MathBlockNode({super.debugHtmlNode, required this.texSource});
339+
class KatexSpan extends ContentNode {
340+
const KatexSpan({
341+
required this.spanClasses,
342+
required this.spanStyle,
343+
required this.text,
344+
this.spans = const [],
345+
});
339346

340-
final String texSource;
347+
final List<String> spanClasses;
348+
final KatexSpanStyle? spanStyle;
349+
final String? text;
350+
final List<KatexSpan> spans;
341351

342352
@override
343-
bool operator ==(Object other) {
344-
return other is MathBlockNode && other.texSource == texSource;
353+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
354+
super.debugFillProperties(properties);
355+
properties.add(StringProperty('spanClass', spanClasses.join(', ')));
356+
properties.add(KatexSpanStyleProperty('spanStyle', spanStyle));
357+
properties.add(StringProperty('text', text));
345358
}
346359

347360
@override
348-
int get hashCode => Object.hash('MathBlockNode', texSource);
361+
List<DiagnosticsNode> debugDescribeChildren() {
362+
return spans.map((node) => node.toDiagnosticsNode()).toList();
363+
}
364+
}
365+
366+
class MathBlockNode extends BlockContentNode {
367+
const MathBlockNode({
368+
super.debugHtmlNode,
369+
required this.texSource,
370+
required this.spans,
371+
});
372+
373+
final String texSource;
374+
final List<KatexSpan> spans;
349375

350376
@override
351-
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
352-
super.debugFillProperties(properties);
353-
properties.add(StringProperty('texSource', texSource));
377+
List<DiagnosticsNode> debugDescribeChildren() {
378+
return spans.map((node) => node.toDiagnosticsNode()).toList();
354379
}
355380
}
356381

@@ -1055,12 +1080,12 @@ class _ZulipContentParser {
10551080
return inlineParser.parseBlockInline(nodes);
10561081
}
10571082

1058-
BlockContentNode parseMathBlock(dom.Element element) {
1059-
final debugHtmlNode = kDebugMode ? element : null;
1060-
final texSource = _parseMath(element, block: true);
1061-
if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
1062-
return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1063-
}
1083+
// BlockContentNode parseMathBlock(dom.Element element) {
1084+
// final debugHtmlNode = kDebugMode ? element : null;
1085+
// final texSource = _parseMath(element, block: true);
1086+
// if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
1087+
// return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1088+
// }
10641089

10651090
BlockContentNode parseListNode(dom.Element element) {
10661091
ListStyle? listStyle;
@@ -1453,6 +1478,29 @@ class _ZulipContentParser {
14531478
return tableNode ?? UnimplementedBlockContentNode(htmlNode: tableElement);
14541479
}
14551480

1481+
BlockContentNode? parseKatexBlock(dom.Element element) {
1482+
assert(element.localName == 'span' && element.className == 'katex-display');
1483+
if (element.nodes.length != 1) return null;
1484+
final child = element.nodes.single;
1485+
if (child is! dom.Element) return null;
1486+
if (child.localName != 'span') return null;
1487+
if (child.className != 'katex') return null;
1488+
1489+
if (child.nodes.length != 2) return null;
1490+
final grandchild = child.nodes.last;
1491+
if (grandchild is! dom.Element) return null;
1492+
if (grandchild.localName != 'span') return null;
1493+
if (grandchild.className != 'katex-html') return null;
1494+
1495+
try {
1496+
final spans = parseKatexSpans(grandchild);
1497+
return MathBlockNode(texSource: '', spans: spans);
1498+
} on KatexHtmlParseError catch (e, st) {
1499+
print('$e\n$st');
1500+
return null;
1501+
}
1502+
}
1503+
14561504
BlockContentNode parseBlockContent(dom.Node node) {
14571505
final debugHtmlNode = kDebugMode ? node : null;
14581506
if (node is! dom.Element) {
@@ -1474,15 +1522,18 @@ class _ZulipContentParser {
14741522
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
14751523
if (element.nodes case [dom.Element(localName: 'span') && var child, ...]) {
14761524
if (child.className == 'katex-display') {
1477-
if (element.nodes case [_]
1478-
|| [_, dom.Element(localName: 'br'),
1479-
dom.Text(text: "\n")]) {
1480-
// This might be too specific; we'll find out when we do #190.
1481-
// The case with the `<br>\n` can happen when at the end of a quote;
1482-
// it seems like a glitch in the server's Markdown processing,
1483-
// so hopefully there just aren't any further such glitches.
1484-
return parseMathBlock(child);
1485-
}
1525+
// if (element.nodes case [_]
1526+
// || [_, dom.Element(localName: 'br'),
1527+
// dom.Text(text: "\n")]) {
1528+
// // This might be too specific; we'll find out when we do #190.
1529+
// // The case with the `<br>\n` can happen when at the end of a quote;
1530+
// // it seems like a glitch in the server's Markdown processing,
1531+
// // so hopefully there just aren't any further such glitches.
1532+
// return parseMathBlock(child);
1533+
// }
1534+
final block = parseKatexBlock(child);
1535+
if (block == null) return UnimplementedBlockContentNode(htmlNode: child);
1536+
return block;
14861537
}
14871538
}
14881539

0 commit comments

Comments
 (0)