feat: support formula in DeltaMarkdownDecoder (#1155)

This commit is contained in:
Morn 2025-11-11 09:41:26 +08:00 • committed by GitHub
commit c643df7c9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 45 additions and 1 deletions

View file

@ -3,7 +3,7 @@
/// bold, italic, /// bold, italic,
/// underline, strikethrough, /// underline, strikethrough,
/// textColor, highlightColor, /// textColor, highlightColor,
/// href /// href, formula
/// ///
/// Supported global rendering types: /// Supported global rendering types:
/// heading: h1, h2, h3, h4, h5, h6, ... /// heading: h1, h2, h3, h4, h5, h6, ...
@ -20,6 +20,7 @@ class BuiltInAttributeKey {
static String highlightColor = 'highlightColor'; static String highlightColor = 'highlightColor';
static String code = 'code'; static String code = 'code';
static String href = 'href'; static String href = 'href';
static String formula = 'formula';
static String subtype = 'subtype'; static String subtype = 'subtype';
static String heading = 'heading'; static String heading = 'heading';

View file

@ -0,0 +1,18 @@
import 'package:markdown/markdown.dart' as md;
class FormulaInlineSyntax extends md.InlineSyntax {
FormulaInlineSyntax() : super(r'(?<!\$)\$(?!\$)([\s\S]+?)(?<!\$)\$(?!\$)');
@override
bool onMatch(md.InlineParser parser, Match match) {
final formula = match.group(1);
if (formula == null || formula.isEmpty) {
return false;
}
final element = md.Element('formula', [md.Text('\$')]);
element.attributes['formula'] = formula;
parser.addNode(element);
return true;
}
}

View file

@ -6,6 +6,8 @@ import 'package:appflowy_editor/src/core/legacy/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart'; import 'package:appflowy_editor/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart';
import 'package:markdown/markdown.dart' as md; import 'package:markdown/markdown.dart' as md;
import 'custom_syntaxes/formula_syntax.dart';
class DeltaMarkdownDecoder extends Converter<String, Delta> class DeltaMarkdownDecoder extends Converter<String, Delta>
implements md.NodeVisitor { implements md.NodeVisitor {
final _delta = Delta(); final _delta = Delta();
@ -20,6 +22,7 @@ class DeltaMarkdownDecoder extends Converter<String, Delta>
Delta convert(String input) { Delta convert(String input) {
final inlineSyntaxes = [ final inlineSyntaxes = [
UnderlineInlineSyntax(), UnderlineInlineSyntax(),
FormulaInlineSyntax(),
...customInlineSyntaxes, ...customInlineSyntaxes,
]; ];
final document = md.Document( final document = md.Document(
@ -73,6 +76,8 @@ class DeltaMarkdownDecoder extends Converter<String, Delta>
_attributes[BuiltInAttributeKey.href] = element.attributes['href']; _attributes[BuiltInAttributeKey.href] = element.attributes['href'];
} else if (element.tag == 'u') { } else if (element.tag == 'u') {
_attributes[BuiltInAttributeKey.underline] = true; _attributes[BuiltInAttributeKey.underline] = true;
} else if (element.tag == 'formula') {
_attributes[BuiltInAttributeKey.formula] = element.attributes['formula'];
} else { } else {
element.attributes.forEach((key, value) { element.attributes.forEach((key, value) {
try { try {
@ -97,6 +102,8 @@ class DeltaMarkdownDecoder extends Converter<String, Delta>
_attributes.remove(BuiltInAttributeKey.href); _attributes.remove(BuiltInAttributeKey.href);
} else if (element.tag == 'u') { } else if (element.tag == 'u') {
_attributes.remove(BuiltInAttributeKey.underline); _attributes.remove(BuiltInAttributeKey.underline);
} else if (element.tag == 'formula') {
_attributes.remove(BuiltInAttributeKey.formula);
} else { } else {
for (final key in element.attributes.keys) { for (final key in element.attributes.keys) {
_attributes.remove(key); _attributes.remove(key);

View file

@ -5,6 +5,8 @@ import 'package:appflowy_editor/src/plugins/markdown/decoder/custom_syntaxes/und
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:markdown/markdown.dart' as md; import 'package:markdown/markdown.dart' as md;
import 'custom_syntaxes/formula_syntax.dart';
class DocumentMarkdownDecoder extends Converter<String, Document> { class DocumentMarkdownDecoder extends Converter<String, Document> {
DocumentMarkdownDecoder({ DocumentMarkdownDecoder({
this.markdownElementParsers = const [], this.markdownElementParsers = const [],
@ -21,6 +23,7 @@ class DocumentMarkdownDecoder extends Converter<String, Document> {
extensionSet: md.ExtensionSet.gitHubFlavored, extensionSet: md.ExtensionSet.gitHubFlavored,
inlineSyntaxes: [ inlineSyntaxes: [
...inlineSyntaxes, ...inlineSyntaxes,
FormulaInlineSyntax(),
UnderlineInlineSyntax(), UnderlineInlineSyntax(),
], ],
encodeHtml: false, encodeHtml: false,

View file

@ -121,5 +121,20 @@ void main() async {
final result = DeltaMarkdownDecoder().convert(markdown); final result = DeltaMarkdownDecoder().convert(markdown);
expect(result, delta); expect(result, delta);
}); });
test('formula', () {
const markdown = 'This is a math equation \$E = MC ^ 2\$';
final delta = Delta(
operations: [
TextInsert('This is a math equation '),
TextInsert(
'\$',
attributes: {BuiltInAttributeKey.formula: 'E = MC ^ 2'},
),
],
);
final result = DeltaMarkdownDecoder().convert(markdown);
expect(result, delta);
});
}); });
} }