mirror of
https://github.com/flame-engine/flame.git
synced 2025-10-31 00:48:47 +08:00
feat: Support inline code blocks on markdown rich text (#3186)
Support inline code blocks on markdown rich text.
This commit is contained in:
@ -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(
|
||||||
|
|||||||
24
packages/flame/lib/src/text/nodes/code_text_node.dart
Normal file
24
packages/flame/lib/src/text/nodes/code_text_node.dart
Normal 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;
|
||||||
|
}
|
||||||
@ -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?,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user