81 lines
2.6 KiB
Dart
81 lines
2.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:markdown_widget/markdown_widget.dart';
|
|
import 'package:flutter_math_fork/flutter_math.dart';
|
|
import 'package:markdown/markdown.dart' as m;
|
|
|
|
SpanNodeGeneratorWithTag latexGenerator = SpanNodeGeneratorWithTag(
|
|
tag: _latexTag,
|
|
generator:
|
|
(e, config, visitor) => LatexNode(e.attributes, e.textContent, config),
|
|
);
|
|
|
|
const _latexTag = 'latex';
|
|
|
|
class LatexSyntax extends m.InlineSyntax {
|
|
final bool isDark;
|
|
LatexSyntax(this.isDark) : super(r'(\$\$[\s\S]+\$\$)|(\$.+?\$)');
|
|
|
|
@override
|
|
bool onMatch(m.InlineParser parser, Match match) {
|
|
final input = match.input;
|
|
final matchValue = input.substring(match.start, match.end);
|
|
String content = '';
|
|
bool isInline = true;
|
|
const blockSyntax = '\$\$';
|
|
const inlineSyntax = '\$';
|
|
if (matchValue.startsWith(blockSyntax) &&
|
|
matchValue.endsWith(blockSyntax) &&
|
|
(matchValue != blockSyntax)) {
|
|
content = matchValue.substring(2, matchValue.length - 2);
|
|
isInline = false;
|
|
} else if (matchValue.startsWith(inlineSyntax) &&
|
|
matchValue.endsWith(inlineSyntax) &&
|
|
matchValue != inlineSyntax) {
|
|
content = matchValue.substring(1, matchValue.length - 1);
|
|
}
|
|
m.Element el = m.Element.text(_latexTag, matchValue);
|
|
el.attributes['content'] = content;
|
|
el.attributes['isInline'] = '$isInline';
|
|
el.attributes['isDark'] = isDark.toString();
|
|
parser.addNode(el);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class LatexNode extends SpanNode {
|
|
final Map<String, String> attributes;
|
|
final String textContent;
|
|
final MarkdownConfig config;
|
|
|
|
LatexNode(this.attributes, this.textContent, this.config);
|
|
|
|
@override
|
|
InlineSpan build() {
|
|
final content = attributes['content'] ?? '';
|
|
final isInline = attributes['isInline'] == 'true';
|
|
final isDark = attributes['isDark'] == 'true';
|
|
final style = parentStyle ?? config.p.textStyle;
|
|
if (content.isEmpty) return TextSpan(style: style, text: textContent);
|
|
final latex = Math.tex(
|
|
content,
|
|
mathStyle: MathStyle.text,
|
|
textStyle: style.copyWith(color: isDark ? Colors.white : Colors.black),
|
|
textScaleFactor: 1,
|
|
onErrorFallback: (error) {
|
|
return Text(textContent, style: style.copyWith(color: Colors.red));
|
|
},
|
|
);
|
|
return WidgetSpan(
|
|
alignment: PlaceholderAlignment.middle,
|
|
child:
|
|
!isInline
|
|
? Container(
|
|
width: double.infinity,
|
|
margin: EdgeInsets.symmetric(vertical: 16),
|
|
child: Center(child: latex),
|
|
)
|
|
: latex,
|
|
);
|
|
}
|
|
}
|