Skip to content

Commit 132519e

Browse files
content: Make CodeBlockSpanNode take a list of span types
But only allowing a single element for now, making the diff for content tests simpler for the later commit which implements support for multiple span types. Also better formatting for code block HTML in content tests.
1 parent 2f9a8f6 commit 132519e

File tree

3 files changed

+92
-66
lines changed

3 files changed

+92
-66
lines changed

lib/model/content.dart

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -320,24 +320,30 @@ class CodeBlockNode extends BlockContentNode {
320320
}
321321

322322
class CodeBlockSpanNode extends ContentNode {
323-
const CodeBlockSpanNode({super.debugHtmlNode, required this.text, required this.type});
323+
const CodeBlockSpanNode({
324+
super.debugHtmlNode,
325+
required this.text,
326+
required this.spanTypes,
327+
}) : assert(spanTypes.length == 1);
324328

325329
final String text;
326-
final CodeBlockSpanType type;
330+
final List<CodeBlockSpanType> spanTypes;
327331

328332
@override
329333
bool operator ==(Object other) {
330-
return other is CodeBlockSpanNode && other.text == text && other.type == type;
334+
return other is CodeBlockSpanNode &&
335+
other.text == text &&
336+
other.spanTypes == spanTypes;
331337
}
332338

333339
@override
334-
int get hashCode => Object.hash('CodeBlockSpanNode', text, type);
340+
int get hashCode => Object.hash('CodeBlockSpanNode', text, spanTypes);
335341

336342
@override
337343
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
338344
super.debugFillProperties(properties);
339345
properties.add(StringProperty('text', text));
340-
properties.add(EnumProperty('type', type));
346+
properties.add(StringProperty('spanTypes', spanTypes.toString()));
341347
}
342348
}
343349

@@ -1237,7 +1243,7 @@ class _ZulipContentParser {
12371243
if (text.isEmpty) {
12381244
continue;
12391245
}
1240-
span = CodeBlockSpanNode(text: text, type: CodeBlockSpanType.text);
1246+
span = CodeBlockSpanNode(text: text, spanTypes: const [CodeBlockSpanType.text]);
12411247

12421248
case dom.Element(localName: 'span', :final text, :final className):
12431249
// Empirically, when a Pygments node has multiple classes, the first
@@ -1258,7 +1264,7 @@ class _ZulipContentParser {
12581264
// inherited styles for `span.hll` nodes.
12591265
return UnimplementedBlockContentNode(htmlNode: divElement);
12601266
default:
1261-
span = CodeBlockSpanNode(text: text, type: spanType);
1267+
span = CodeBlockSpanNode(text: text, spanTypes: [spanType]);
12621268
}
12631269

12641270
default:

lib/widgets/content.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ class CodeBlock extends StatelessWidget {
784784
child: Text.rich(TextSpan(
785785
style: styles.plain,
786786
children: node.spans
787-
.map((node) => TextSpan(style: styles.forSpan(node.type), text: node.text))
787+
.map((node) => TextSpan(style: styles.forSpan(node.spanTypes.single), text: node.text))
788788
.toList(growable: false))));
789789
}
790790
}

test/model/content_test.dart

Lines changed: 78 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -382,86 +382,105 @@ class ContentExample {
382382
QuotationNode([ParagraphNode(links: null, nodes: [TextNode('words')])])
383383
]);
384384

385-
static const codeBlockPlain = ContentExample(
385+
static final codeBlockPlain = ContentExample(
386386
'code block without syntax highlighting',
387387
"```\nverb\natim\n```",
388388
expectedText: 'verb\natim',
389-
'<div class="codehilite"><pre><span></span><code>verb\natim\n</code></pre></div>', [
389+
'<div class="codehilite">'
390+
'<pre><span></span>'
391+
'<code>verb\natim\n</code></pre></div>', [
390392
CodeBlockNode([
391-
CodeBlockSpanNode(text: 'verb\natim', type: CodeBlockSpanType.text),
393+
CodeBlockSpanNode(text: 'verb\natim', spanTypes: [CodeBlockSpanType.text]),
392394
]),
393395
]);
394396

395-
static const codeBlockHighlightedShort = ContentExample(
397+
static final codeBlockHighlightedShort = ContentExample(
396398
'code block with syntax highlighting',
397399
"```dart\nclass A {}\n```",
398400
expectedText: 'class A {}',
399-
'<div class="codehilite" data-code-language="Dart"><pre>'
400-
'<span></span><code><span class="kd">class</span><span class="w"> </span>'
401-
'<span class="nc">A</span><span class="w"> </span><span class="p">{}</span>'
402-
'\n</code></pre></div>', [
401+
'<div class="codehilite" data-code-language="Dart">'
402+
'<pre><span></span>'
403+
'<code>'
404+
'<span class="kd">class</span>'
405+
'<span class="w"> </span>'
406+
'<span class="nc">A</span>'
407+
'<span class="w"> </span>'
408+
'<span class="p">{}</span>\n</code></pre></div>', [
403409
CodeBlockNode([
404-
CodeBlockSpanNode(text: 'class', type: CodeBlockSpanType.keywordDeclaration),
405-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
406-
CodeBlockSpanNode(text: 'A', type: CodeBlockSpanType.nameClass),
407-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
408-
CodeBlockSpanNode(text: '{}', type: CodeBlockSpanType.punctuation),
410+
CodeBlockSpanNode(text: 'class', spanTypes: [CodeBlockSpanType.keywordDeclaration]),
411+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
412+
CodeBlockSpanNode(text: 'A', spanTypes: [CodeBlockSpanType.nameClass]),
413+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
414+
CodeBlockSpanNode(text: '{}', spanTypes: [CodeBlockSpanType.punctuation]),
409415
]),
410416
]);
411417

412-
static const codeBlockHighlightedMultiline = ContentExample(
418+
static final codeBlockHighlightedMultiline = ContentExample(
413419
'code block, multiline, with syntax highlighting',
414420
'```rust\nfn main() {\n print!("Hello ");\n\n print!("world!\\n");\n}\n```',
415421
expectedText: 'fn main() {\n print!("Hello ");\n\n print!("world!\\n");\n}',
416-
'<div class="codehilite" data-code-language="Rust"><pre>'
417-
'<span></span><code><span class="k">fn</span> <span class="nf">main</span>'
418-
'<span class="p">()</span><span class="w"> </span><span class="p">{</span>\n'
419-
'<span class="w"> </span><span class="fm">print!</span><span class="p">(</span>'
420-
'<span class="s">"Hello "</span><span class="p">);</span>\n\n'
421-
'<span class="w"> </span><span class="fm">print!</span><span class="p">(</span>'
422-
'<span class="s">"world!</span><span class="se">\\n</span><span class="s">"</span>'
423-
'<span class="p">);</span>\n<span class="p">}</span>\n'
424-
'</code></pre></div>', [
422+
'<div class="codehilite" data-code-language="Rust">'
423+
'<pre><span></span>'
424+
'<code>'
425+
'<span class="k">fn</span> '
426+
'<span class="nf">main</span>'
427+
'<span class="p">()</span>'
428+
'<span class="w"> </span>'
429+
'<span class="p">{</span>\n'
430+
'<span class="w"> </span>'
431+
'<span class="fm">print!</span>'
432+
'<span class="p">(</span>'
433+
'<span class="s">"Hello "</span>'
434+
'<span class="p">);</span>\n\n'
435+
'<span class="w"> </span>'
436+
'<span class="fm">print!</span>'
437+
'<span class="p">(</span>'
438+
'<span class="s">"world!</span>'
439+
'<span class="se">\\n</span>'
440+
'<span class="s">"</span>'
441+
'<span class="p">);</span>\n'
442+
'<span class="p">}</span>\n</code></pre></div>', [
425443
CodeBlockNode([
426-
CodeBlockSpanNode(text: 'fn', type: CodeBlockSpanType.keyword),
427-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.text),
428-
CodeBlockSpanNode(text: 'main', type: CodeBlockSpanType.nameFunction),
429-
CodeBlockSpanNode(text: '()', type: CodeBlockSpanType.punctuation),
430-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
431-
CodeBlockSpanNode(text: '{', type: CodeBlockSpanType.punctuation),
432-
CodeBlockSpanNode(text: '\n', type: CodeBlockSpanType.text),
433-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
434-
CodeBlockSpanNode(text: 'print!', type: CodeBlockSpanType.nameFunctionMagic),
435-
CodeBlockSpanNode(text: '(', type: CodeBlockSpanType.punctuation),
436-
CodeBlockSpanNode(text: '"Hello "', type: CodeBlockSpanType.string),
437-
CodeBlockSpanNode(text: ');', type: CodeBlockSpanType.punctuation),
438-
CodeBlockSpanNode(text: '\n\n', type: CodeBlockSpanType.text),
439-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
440-
CodeBlockSpanNode(text: 'print!', type: CodeBlockSpanType.nameFunctionMagic),
441-
CodeBlockSpanNode(text: '(', type: CodeBlockSpanType.punctuation),
442-
CodeBlockSpanNode(text: '"world!', type: CodeBlockSpanType.string),
443-
CodeBlockSpanNode(text: '\\n', type: CodeBlockSpanType.stringEscape),
444-
CodeBlockSpanNode(text: '"', type: CodeBlockSpanType.string),
445-
CodeBlockSpanNode(text: ');', type: CodeBlockSpanType.punctuation),
446-
CodeBlockSpanNode(text: '\n', type: CodeBlockSpanType.text),
447-
CodeBlockSpanNode(text: '}', type: CodeBlockSpanType.punctuation),
444+
CodeBlockSpanNode(text: 'fn', spanTypes: [CodeBlockSpanType.keyword]),
445+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.text]),
446+
CodeBlockSpanNode(text: 'main', spanTypes: [CodeBlockSpanType.nameFunction]),
447+
CodeBlockSpanNode(text: '()', spanTypes: [CodeBlockSpanType.punctuation]),
448+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
449+
CodeBlockSpanNode(text: '{', spanTypes: [CodeBlockSpanType.punctuation]),
450+
CodeBlockSpanNode(text: '\n', spanTypes: [CodeBlockSpanType.text]),
451+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
452+
CodeBlockSpanNode(text: 'print!', spanTypes: [CodeBlockSpanType.nameFunctionMagic]),
453+
CodeBlockSpanNode(text: '(', spanTypes: [CodeBlockSpanType.punctuation]),
454+
CodeBlockSpanNode(text: '"Hello "', spanTypes: [CodeBlockSpanType.string]),
455+
CodeBlockSpanNode(text: ');', spanTypes: [CodeBlockSpanType.punctuation]),
456+
CodeBlockSpanNode(text: '\n\n', spanTypes: [CodeBlockSpanType.text]),
457+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
458+
CodeBlockSpanNode(text: 'print!', spanTypes: [CodeBlockSpanType.nameFunctionMagic]),
459+
CodeBlockSpanNode(text: '(', spanTypes: [CodeBlockSpanType.punctuation]),
460+
CodeBlockSpanNode(text: '"world!', spanTypes: [CodeBlockSpanType.string]),
461+
CodeBlockSpanNode(text: '\\n', spanTypes: [CodeBlockSpanType.stringEscape]),
462+
CodeBlockSpanNode(text: '"', spanTypes: [CodeBlockSpanType.string]),
463+
CodeBlockSpanNode(text: ');', spanTypes: [CodeBlockSpanType.punctuation]),
464+
CodeBlockSpanNode(text: '\n', spanTypes: [CodeBlockSpanType.text]),
465+
CodeBlockSpanNode(text: '}', spanTypes: [CodeBlockSpanType.punctuation]),
448466
]),
449467
]);
450468

451-
static const codeBlockSpansWithMultipleClasses = ContentExample(
469+
static final codeBlockSpansWithMultipleClasses = ContentExample(
452470
'code block spans with multiple CSS classes',
453471
'```yaml\n- item\n```',
454472
expectedText: '- item',
455473
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/Greg/near/1949014
456474
'<div class="codehilite" data-code-language="YAML">'
457-
'<pre><span></span><code><span class="p p-Indicator">-</span>'
458-
'<span class="w"> </span>'
459-
'<span class="l l-Scalar l-Scalar-Plain">item</span>\n'
460-
'</code></pre></div>', [
475+
'<pre><span></span>'
476+
'<code>'
477+
'<span class="p p-Indicator">-</span>'
478+
'<span class="w"> </span>'
479+
'<span class="l l-Scalar l-Scalar-Plain">item</span>\n</code></pre></div>', [
461480
CodeBlockNode([
462-
CodeBlockSpanNode(text: "-", type: CodeBlockSpanType.punctuation),
463-
CodeBlockSpanNode(text: " ", type: CodeBlockSpanType.whitespace),
464-
CodeBlockSpanNode(text: "item", type: CodeBlockSpanType.literal)
481+
CodeBlockSpanNode(text: "-", spanTypes: [CodeBlockSpanType.punctuation]),
482+
CodeBlockSpanNode(text: " ", spanTypes: [CodeBlockSpanType.whitespace]),
483+
CodeBlockSpanNode(text: "item", spanTypes: [CodeBlockSpanType.literal])
465484
]),
466485
]);
467486

@@ -505,14 +524,15 @@ class ContentExample {
505524
'\n</code></pre></div>'),
506525
]);
507526

508-
static const codeBlockFollowedByMultipleLineBreaks = ContentExample(
527+
static final codeBlockFollowedByMultipleLineBreaks = ContentExample(
509528
'blank text nodes after code blocks',
510529
' code block.\n\nsome content',
511530
// https://chat.zulip.org/#narrow/stream/7-test-here/near/1774823
512531
'<div class="codehilite">'
513-
'<pre><span></span><code>code block.\n</code></pre></div>\n\n'
532+
'<pre><span></span>'
533+
'<code>code block.\n</code></pre></div>\n\n'
514534
'<p>some content</p>', [
515-
CodeBlockNode([CodeBlockSpanNode(text: "code block.", type: CodeBlockSpanType.text)]),
535+
CodeBlockNode([CodeBlockSpanNode(text: "code block.", spanTypes: [CodeBlockSpanType.text])]),
516536
ParagraphNode(links: null, nodes: [TextNode("some content")]),
517537
]);
518538

@@ -2040,7 +2060,7 @@ void main() async {
20402060
// "1. > ###### two\n > * three\n\n four"
20412061
'<ol>\n<li>\n<blockquote>\n<h6>two</h6>\n<ul>\n<li>three</li>\n'
20422062
'</ul>\n</blockquote>\n<div class="codehilite"><pre><span></span>'
2043-
'<code>four\n</code></pre></div>\n\n</li>\n</ol>', const [
2063+
'<code>four\n</code></pre></div>\n\n</li>\n</ol>', [
20442064
OrderedListNode(start: 1, [[
20452065
QuotationNode([
20462066
HeadingNode(level: HeadingLevel.h6, links: null, nodes: [TextNode('two')]),
@@ -2049,7 +2069,7 @@ void main() async {
20492069
]]),
20502070
]),
20512071
CodeBlockNode([
2052-
CodeBlockSpanNode(text: 'four', type: CodeBlockSpanType.text),
2072+
CodeBlockSpanNode(text: 'four', spanTypes: [CodeBlockSpanType.text]),
20532073
]),
20542074
ParagraphNode(wasImplicit: true, links: null, nodes: [TextNode('\n\n')]), // TODO avoid this; it renders wrong
20552075
]]),

0 commit comments

Comments
 (0)