feat: Support inline code blocks on markdown rich text (#3186)

Support inline code blocks on markdown rich text.
This commit is contained in:
Luan Nico
2024-06-06 05:57:55 -07:00
committed by GitHub
parent 7c40034d20
commit 67e069c00d
6 changed files with 69 additions and 8 deletions

View File

@ -58,14 +58,24 @@ class RichTextExample extends FlameGame {
PlainTextNode('."'), PlainTextNode('."'),
]), ]),
]), ]),
ParagraphNode.simple( ParagraphNode.group([
'He pushed the thought under instantly. The fallacy was obvious. It ' PlainTextNode(
'presupposed that somewhere or other, outside oneself, there was a ' 'He pushed the thought under instantly. The fallacy was obvious. It '
'"real" world where "real" things happened. But how could there be ' 'presupposed that somewhere or other, outside oneself, there was a '
'such a world? What knowledge have we of anything, save through our ' '"',
'own minds? All happenings are in the mind. Whatever happens in all ' ),
'minds, truly happens.', CodeTextNode.simple('real'),
), PlainTextNode(
'" world where "',
),
CodeTextNode.simple('real'),
PlainTextNode(
'" things happened. But how could there be '
'such a world? What knowledge have we of anything, save through our '
'own minds? All happenings are in the mind. Whatever happens in all '
'minds, truly happens.',
),
]),
]); ]);
add( add(

View File

@ -0,0 +1,24 @@
import 'package:flame/src/text/nodes/inline_text_node.dart';
import 'package:flame/text.dart';
class CodeTextNode extends InlineTextNode {
CodeTextNode(this.child);
CodeTextNode.simple(String text) : child = PlainTextNode(text);
CodeTextNode.group(List<InlineTextNode> children)
: child = GroupTextNode(children);
final InlineTextNode child;
static final defaultStyle = InlineTextStyle(fontFamily: 'monospace');
@override
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = FlameTextStyle.merge(parentTextStyle, stylesheet.codeText)!;
child.fillStyles(stylesheet, style);
}
@override
TextNodeLayoutBuilder get layoutBuilder => child.layoutBuilder;
}

View File

@ -20,6 +20,7 @@ class DocumentStyle extends FlameTextStyle {
InlineTextStyle? text, InlineTextStyle? text,
InlineTextStyle? boldText, InlineTextStyle? boldText,
InlineTextStyle? italicText, InlineTextStyle? italicText,
InlineTextStyle? codeText,
BlockStyle? paragraph, BlockStyle? paragraph,
BlockStyle? header1, BlockStyle? header1,
BlockStyle? header2, BlockStyle? header2,
@ -31,6 +32,7 @@ class DocumentStyle extends FlameTextStyle {
_boldText = FlameTextStyle.merge(BoldTextNode.defaultStyle, boldText), _boldText = FlameTextStyle.merge(BoldTextNode.defaultStyle, boldText),
_italicText = _italicText =
FlameTextStyle.merge(ItalicTextNode.defaultStyle, italicText), FlameTextStyle.merge(ItalicTextNode.defaultStyle, italicText),
_codeText = FlameTextStyle.merge(CodeTextNode.defaultStyle, codeText),
_paragraph = _paragraph =
FlameTextStyle.merge(ParagraphNode.defaultStyle, paragraph), FlameTextStyle.merge(ParagraphNode.defaultStyle, paragraph),
_header1 = FlameTextStyle.merge(HeaderNode.defaultStyleH1, header1), _header1 = FlameTextStyle.merge(HeaderNode.defaultStyleH1, header1),
@ -43,6 +45,7 @@ class DocumentStyle extends FlameTextStyle {
final InlineTextStyle? _text; final InlineTextStyle? _text;
final InlineTextStyle? _boldText; final InlineTextStyle? _boldText;
final InlineTextStyle? _italicText; final InlineTextStyle? _italicText;
final InlineTextStyle? _codeText;
final BlockStyle? _paragraph; final BlockStyle? _paragraph;
final BlockStyle? _header1; final BlockStyle? _header1;
final BlockStyle? _header2; final BlockStyle? _header2;
@ -94,6 +97,7 @@ class DocumentStyle extends FlameTextStyle {
InlineTextStyle get text => _text!; InlineTextStyle get text => _text!;
InlineTextStyle get boldText => _boldText!; InlineTextStyle get boldText => _boldText!;
InlineTextStyle get italicText => _italicText!; InlineTextStyle get italicText => _italicText!;
InlineTextStyle get codeText => _codeText!;
/// Style for [ParagraphNode]s. /// Style for [ParagraphNode]s.
BlockStyle get paragraph => _paragraph!; BlockStyle get paragraph => _paragraph!;
@ -117,6 +121,7 @@ class DocumentStyle extends FlameTextStyle {
text: FlameTextStyle.merge(_text, other.text), text: FlameTextStyle.merge(_text, other.text),
boldText: FlameTextStyle.merge(_boldText, other.boldText), boldText: FlameTextStyle.merge(_boldText, other.boldText),
italicText: FlameTextStyle.merge(_italicText, other.italicText), italicText: FlameTextStyle.merge(_italicText, other.italicText),
codeText: FlameTextStyle.merge(_codeText, other.codeText),
background: merge(background, other.background) as BackgroundStyle?, background: merge(background, other.background) as BackgroundStyle?,
paragraph: merge(paragraph, other.paragraph) as BlockStyle?, paragraph: merge(paragraph, other.paragraph) as BlockStyle?,
header1: merge(header1, other.header1) as BlockStyle?, header1: merge(header1, other.header1) as BlockStyle?,

View File

@ -14,6 +14,7 @@ export 'src/text/elements/text_painter_text_element.dart'
show TextPainterTextElement; show TextPainterTextElement;
export 'src/text/nodes/block_node.dart' show BlockNode; export 'src/text/nodes/block_node.dart' show BlockNode;
export 'src/text/nodes/bold_text_node.dart' show BoldTextNode; export 'src/text/nodes/bold_text_node.dart' show BoldTextNode;
export 'src/text/nodes/code_text_node.dart' show CodeTextNode;
export 'src/text/nodes/column_node.dart' show ColumnNode; export 'src/text/nodes/column_node.dart' show ColumnNode;
export 'src/text/nodes/document_root.dart' show DocumentRoot; export 'src/text/nodes/document_root.dart' show DocumentRoot;
export 'src/text/nodes/group_text_node.dart' show GroupTextNode; export 'src/text/nodes/group_text_node.dart' show GroupTextNode;

View File

@ -55,6 +55,7 @@ class FlameMarkdown {
'p' => ParagraphNode(child), 'p' => ParagraphNode(child),
'em' || 'i' => ItalicTextNode(child), 'em' || 'i' => ItalicTextNode(child),
'strong' || 'b' => BoldTextNode(child), 'strong' || 'b' => BoldTextNode(child),
'code' => CodeTextNode(child),
_ => throw Exception('Unknown element tag: ${element.tag}'), _ => throw Exception('Unknown element tag: ${element.tag}'),
} as TextNode; } as TextNode;
} }

View File

@ -29,6 +29,19 @@ void main() {
]); ]);
}); });
test('inline code block', () {
final doc = FlameMarkdown.toDocument('Flame: `var game = FlameGame();`');
_expectDocument(doc, [
(node) => _expectParagraph(node, (p) {
_expectGroup(p, [
(node) => _expectPlain(node, 'Flame: '),
(node) => _expectCode(node, 'var game = FlameGame();'),
]);
}),
]);
});
test('all header levels', () { test('all header levels', () {
final doc = FlameMarkdown.toDocument( final doc = FlameMarkdown.toDocument(
'# h1\n' '# h1\n'
@ -107,6 +120,13 @@ void _expectPlain(InlineTextNode node, String text) {
expect(span.text, text); expect(span.text, text);
} }
void _expectCode(InlineTextNode node, String text) {
expect(node, isA<CodeTextNode>());
final content = (node as CodeTextNode).child;
expect(content, isA<PlainTextNode>());
expect((content as PlainTextNode).text, text);
}
void _expectParagraph( void _expectParagraph(
BlockNode node, BlockNode node,
void Function(InlineTextNode) expectChild, void Function(InlineTextNode) expectChild,