Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rajveermalviya committed Feb 6, 2025
1 parent 61d30f6 commit 6cf134f
Show file tree
Hide file tree
Showing 5 changed files with 979 additions and 56 deletions.
99 changes: 75 additions & 24 deletions lib/model/content.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart';

import '../api/model/model.dart';
import '../api/model/submessage.dart';
import 'code_block.dart';
import 'katex.dart';

/// A node in a parse tree for Zulip message-style content.
///
Expand Down Expand Up @@ -334,23 +336,46 @@ class CodeBlockSpanNode extends ContentNode {
}
}

class MathBlockNode extends BlockContentNode {
const MathBlockNode({super.debugHtmlNode, required this.texSource});
class KatexSpan extends ContentNode {
const KatexSpan({
required this.spanClasses,
required this.spanStyle,
required this.text,
this.spans = const [],
});

final String texSource;
final List<String> spanClasses;
final KatexSpanStyle? spanStyle;
final String? text;
final List<KatexSpan> spans;

@override
bool operator ==(Object other) {
return other is MathBlockNode && other.texSource == texSource;
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(StringProperty('spanClass', spanClasses.join(', ')));
properties.add(KatexSpanStyleProperty('spanStyle', spanStyle));
properties.add(StringProperty('text', text));
}

@override
int get hashCode => Object.hash('MathBlockNode', texSource);
List<DiagnosticsNode> debugDescribeChildren() {
return spans.map((node) => node.toDiagnosticsNode()).toList();
}
}

class MathBlockNode extends BlockContentNode {
const MathBlockNode({
super.debugHtmlNode,
required this.texSource,
required this.spans,
});

final String texSource;
final List<KatexSpan> spans;

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(StringProperty('texSource', texSource));
List<DiagnosticsNode> debugDescribeChildren() {
return spans.map((node) => node.toDiagnosticsNode()).toList();
}
}

Expand Down Expand Up @@ -1055,12 +1080,12 @@ class _ZulipContentParser {
return inlineParser.parseBlockInline(nodes);
}

BlockContentNode parseMathBlock(dom.Element element) {
final debugHtmlNode = kDebugMode ? element : null;
final texSource = _parseMath(element, block: true);
if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
}
// BlockContentNode parseMathBlock(dom.Element element) {
// final debugHtmlNode = kDebugMode ? element : null;
// final texSource = _parseMath(element, block: true);
// if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
// return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
// }

BlockContentNode parseListNode(dom.Element element) {
ListStyle? listStyle;
Expand Down Expand Up @@ -1453,6 +1478,29 @@ class _ZulipContentParser {
return tableNode ?? UnimplementedBlockContentNode(htmlNode: tableElement);
}

BlockContentNode? parseKatexBlock(dom.Element element) {
assert(element.localName == 'span' && element.className == 'katex-display');
if (element.nodes.length != 1) return null;
final child = element.nodes.single;
if (child is! dom.Element) return null;
if (child.localName != 'span') return null;
if (child.className != 'katex') return null;

if (child.nodes.length != 2) return null;
final grandchild = child.nodes.last;
if (grandchild is! dom.Element) return null;
if (grandchild.localName != 'span') return null;
if (grandchild.className != 'katex-html') return null;

try {
final spans = parseKatexSpans(grandchild);
return MathBlockNode(texSource: '', spans: spans);
} on KatexHtmlParseError catch (e, st) {
print('$e\n$st');
return null;
}
}

BlockContentNode parseBlockContent(dom.Node node) {
final debugHtmlNode = kDebugMode ? node : null;
if (node is! dom.Element) {
Expand All @@ -1474,15 +1522,18 @@ class _ZulipContentParser {
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
if (element.nodes case [dom.Element(localName: 'span') && var child, ...]) {
if (child.className == 'katex-display') {
if (element.nodes case [_]
|| [_, dom.Element(localName: 'br'),
dom.Text(text: "\n")]) {
// This might be too specific; we'll find out when we do #190.
// The case with the `<br>\n` can happen when at the end of a quote;
// it seems like a glitch in the server's Markdown processing,
// so hopefully there just aren't any further such glitches.
return parseMathBlock(child);
}
// if (element.nodes case [_]
// || [_, dom.Element(localName: 'br'),
// dom.Text(text: "\n")]) {
// // This might be too specific; we'll find out when we do #190.
// // The case with the `<br>\n` can happen when at the end of a quote;
// // it seems like a glitch in the server's Markdown processing,
// // so hopefully there just aren't any further such glitches.
// return parseMathBlock(child);
// }
final block = parseKatexBlock(child);
if (block == null) return UnimplementedBlockContentNode(htmlNode: child);
return block;
}
}

Expand Down
Loading

0 comments on commit 6cf134f

Please sign in to comment.