Skip to content

Commit

Permalink
feat: Support inline code blocks on markdown rich text
Browse files Browse the repository at this point in the history
  • Loading branch information
luanpotter committed Jun 6, 2024
1 parent 7c40034 commit 5bd5f15
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 8 deletions.
26 changes: 18 additions & 8 deletions examples/lib/stories/rendering/rich_text_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,24 @@ class RichTextExample extends FlameGame {
PlainTextNode('."'),
]),
]),
ParagraphNode.simple(
'He pushed the thought under instantly. The fallacy was obvious. It '
'presupposed that somewhere or other, outside oneself, there was a '
'"real" world where "real" 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.',
),
ParagraphNode.group([
PlainTextNode(
'He pushed the thought under instantly. The fallacy was obvious. It '
'presupposed that somewhere or other, outside oneself, there was a '
'"',
),
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(
Expand Down
24 changes: 24 additions & 0 deletions packages/flame/lib/src/text/nodes/code_text_node.dart
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 5 additions & 0 deletions packages/flame/lib/src/text/styles/document_style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class DocumentStyle extends FlameTextStyle {
InlineTextStyle? text,
InlineTextStyle? boldText,
InlineTextStyle? italicText,
InlineTextStyle? codeText,
BlockStyle? paragraph,
BlockStyle? header1,
BlockStyle? header2,
Expand All @@ -31,6 +32,7 @@ class DocumentStyle extends FlameTextStyle {
_boldText = FlameTextStyle.merge(BoldTextNode.defaultStyle, boldText),
_italicText =
FlameTextStyle.merge(ItalicTextNode.defaultStyle, italicText),
_codeText = FlameTextStyle.merge(CodeTextNode.defaultStyle, codeText),
_paragraph =
FlameTextStyle.merge(ParagraphNode.defaultStyle, paragraph),
_header1 = FlameTextStyle.merge(HeaderNode.defaultStyleH1, header1),
Expand All @@ -43,6 +45,7 @@ class DocumentStyle extends FlameTextStyle {
final InlineTextStyle? _text;
final InlineTextStyle? _boldText;
final InlineTextStyle? _italicText;
final InlineTextStyle? _codeText;
final BlockStyle? _paragraph;
final BlockStyle? _header1;
final BlockStyle? _header2;
Expand Down Expand Up @@ -94,6 +97,7 @@ class DocumentStyle extends FlameTextStyle {
InlineTextStyle get text => _text!;
InlineTextStyle get boldText => _boldText!;
InlineTextStyle get italicText => _italicText!;
InlineTextStyle get codeText => _codeText!;

/// Style for [ParagraphNode]s.
BlockStyle get paragraph => _paragraph!;
Expand All @@ -117,6 +121,7 @@ class DocumentStyle extends FlameTextStyle {
text: FlameTextStyle.merge(_text, other.text),
boldText: FlameTextStyle.merge(_boldText, other.boldText),
italicText: FlameTextStyle.merge(_italicText, other.italicText),
codeText: FlameTextStyle.merge(_codeText, other.codeText),
background: merge(background, other.background) as BackgroundStyle?,
paragraph: merge(paragraph, other.paragraph) as BlockStyle?,
header1: merge(header1, other.header1) as BlockStyle?,
Expand Down
1 change: 1 addition & 0 deletions packages/flame/lib/text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export 'src/text/elements/text_painter_text_element.dart'
show TextPainterTextElement;
export 'src/text/nodes/block_node.dart' show BlockNode;
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/document_root.dart' show DocumentRoot;
export 'src/text/nodes/group_text_node.dart' show GroupTextNode;
Expand Down
1 change: 1 addition & 0 deletions packages/flame_markdown/lib/flame_markdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class FlameMarkdown {
'p' => ParagraphNode(child),
'em' || 'i' => ItalicTextNode(child),
'strong' || 'b' => BoldTextNode(child),
'code' => CodeTextNode(child),
_ => throw Exception('Unknown element tag: ${element.tag}'),
} as TextNode;
}
Expand Down
20 changes: 20 additions & 0 deletions packages/flame_markdown/test/flame_markdown_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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', () {
final doc = FlameMarkdown.toDocument(
'# h1\n'
Expand Down Expand Up @@ -107,6 +120,13 @@ void _expectPlain(InlineTextNode node, String 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(
BlockNode node,
void Function(InlineTextNode) expectChild,
Expand Down

0 comments on commit 5bd5f15

Please sign in to comment.