Skip to content

Commit 981f5b7

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 94037d7 commit 981f5b7

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

@@ -1247,7 +1253,7 @@ class _ZulipContentParser {
12471253
if (text.isEmpty) {
12481254
continue;
12491255
}
1250-
span = CodeBlockSpanNode(text: text, type: CodeBlockSpanType.text);
1256+
span = CodeBlockSpanNode(text: text, spanTypes: const [CodeBlockSpanType.text]);
12511257

12521258
case dom.Element(localName: 'span', :final text, :final className):
12531259
// Empirically, when a Pygments node has multiple classes, the first
@@ -1268,7 +1274,7 @@ class _ZulipContentParser {
12681274
// inherited styles for `span.hll` nodes.
12691275
return UnimplementedBlockContentNode(htmlNode: divElement);
12701276
default:
1271-
span = CodeBlockSpanNode(text: text, type: spanType);
1277+
span = CodeBlockSpanNode(text: text, spanTypes: [spanType]);
12721278
}
12731279

12741280
default:

lib/widgets/content.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ class CodeBlock extends StatelessWidget {
776776
child: Text.rich(TextSpan(
777777
style: styles.plain,
778778
children: node.spans
779-
.map((node) => TextSpan(style: styles.forSpan(node.type), text: node.text))
779+
.map((node) => TextSpan(style: styles.forSpan(node.spanTypes.single), text: node.text))
780780
.toList(growable: false))));
781781
}
782782
}

test/model/content_test.dart

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

378-
static const codeBlockPlain = ContentExample(
378+
static final codeBlockPlain = ContentExample(
379379
'code block without syntax highlighting',
380380
"```\nverb\natim\n```",
381381
expectedText: 'verb\natim',
382-
'<div class="codehilite"><pre><span></span><code>verb\natim\n</code></pre></div>', [
382+
'<div class="codehilite">'
383+
'<pre><span></span>'
384+
'<code>verb\natim\n</code></pre></div>', [
383385
CodeBlockNode([
384-
CodeBlockSpanNode(text: 'verb\natim', type: CodeBlockSpanType.text),
386+
CodeBlockSpanNode(text: 'verb\natim', spanTypes: [CodeBlockSpanType.text]),
385387
]),
386388
]);
387389

388-
static const codeBlockHighlightedShort = ContentExample(
390+
static final codeBlockHighlightedShort = ContentExample(
389391
'code block with syntax highlighting',
390392
"```dart\nclass A {}\n```",
391393
expectedText: 'class A {}',
392-
'<div class="codehilite" data-code-language="Dart"><pre>'
393-
'<span></span><code><span class="kd">class</span><span class="w"> </span>'
394-
'<span class="nc">A</span><span class="w"> </span><span class="p">{}</span>'
395-
'\n</code></pre></div>', [
394+
'<div class="codehilite" data-code-language="Dart">'
395+
'<pre><span></span>'
396+
'<code>'
397+
'<span class="kd">class</span>'
398+
'<span class="w"> </span>'
399+
'<span class="nc">A</span>'
400+
'<span class="w"> </span>'
401+
'<span class="p">{}</span>\n</code></pre></div>', [
396402
CodeBlockNode([
397-
CodeBlockSpanNode(text: 'class', type: CodeBlockSpanType.keywordDeclaration),
398-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
399-
CodeBlockSpanNode(text: 'A', type: CodeBlockSpanType.nameClass),
400-
CodeBlockSpanNode(text: ' ', type: CodeBlockSpanType.whitespace),
401-
CodeBlockSpanNode(text: '{}', type: CodeBlockSpanType.punctuation),
403+
CodeBlockSpanNode(text: 'class', spanTypes: [CodeBlockSpanType.keywordDeclaration]),
404+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
405+
CodeBlockSpanNode(text: 'A', spanTypes: [CodeBlockSpanType.nameClass]),
406+
CodeBlockSpanNode(text: ' ', spanTypes: [CodeBlockSpanType.whitespace]),
407+
CodeBlockSpanNode(text: '{}', spanTypes: [CodeBlockSpanType.punctuation]),
402408
]),
403409
]);
404410

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

444-
static const codeBlockSpansWithMultipleClasses = ContentExample(
462+
static final codeBlockSpansWithMultipleClasses = ContentExample(
445463
'code block spans with multiple CSS classes',
446464
'```yaml\n- item\n```',
447465
expectedText: '- item',
448466
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/Greg/near/1949014
449467
'<div class="codehilite" data-code-language="YAML">'
450-
'<pre><span></span><code><span class="p p-Indicator">-</span>'
451-
'<span class="w"> </span>'
452-
'<span class="l l-Scalar l-Scalar-Plain">item</span>\n'
453-
'</code></pre></div>', [
468+
'<pre><span></span>'
469+
'<code>'
470+
'<span class="p p-Indicator">-</span>'
471+
'<span class="w"> </span>'
472+
'<span class="l l-Scalar l-Scalar-Plain">item</span>\n</code></pre></div>', [
454473
CodeBlockNode([
455-
CodeBlockSpanNode(text: "-", type: CodeBlockSpanType.punctuation),
456-
CodeBlockSpanNode(text: " ", type: CodeBlockSpanType.whitespace),
457-
CodeBlockSpanNode(text: "item", type: CodeBlockSpanType.literal)
474+
CodeBlockSpanNode(text: "-", spanTypes: [CodeBlockSpanType.punctuation]),
475+
CodeBlockSpanNode(text: " ", spanTypes: [CodeBlockSpanType.whitespace]),
476+
CodeBlockSpanNode(text: "item", spanTypes: [CodeBlockSpanType.literal])
458477
]),
459478
]);
460479

@@ -498,14 +517,15 @@ class ContentExample {
498517
'\n</code></pre></div>'),
499518
]);
500519

501-
static const codeBlockFollowedByMultipleLineBreaks = ContentExample(
520+
static final codeBlockFollowedByMultipleLineBreaks = ContentExample(
502521
'blank text nodes after code blocks',
503522
' code block.\n\nsome content',
504523
// https://chat.zulip.org/#narrow/stream/7-test-here/near/1774823
505524
'<div class="codehilite">'
506-
'<pre><span></span><code>code block.\n</code></pre></div>\n\n'
525+
'<pre><span></span>'
526+
'<code>code block.\n</code></pre></div>\n\n'
507527
'<p>some content</p>', [
508-
CodeBlockNode([CodeBlockSpanNode(text: "code block.", type: CodeBlockSpanType.text)]),
528+
CodeBlockNode([CodeBlockSpanNode(text: "code block.", spanTypes: [CodeBlockSpanType.text])]),
509529
ParagraphNode(links: null, nodes: [TextNode("some content")]),
510530
]);
511531

@@ -2079,7 +2099,7 @@ void main() async {
20792099
// "1. > ###### two\n > * three\n\n four"
20802100
'<ol>\n<li>\n<blockquote>\n<h6>two</h6>\n<ul>\n<li>three</li>\n'
20812101
'</ul>\n</blockquote>\n<div class="codehilite"><pre><span></span>'
2082-
'<code>four\n</code></pre></div>\n\n</li>\n</ol>', const [
2102+
'<code>four\n</code></pre></div>\n\n</li>\n</ol>', [
20832103
OrderedListNode(start: 1, [[
20842104
QuotationNode([
20852105
HeadingNode(level: HeadingLevel.h6, links: null, nodes: [TextNode('two')]),
@@ -2088,7 +2108,7 @@ void main() async {
20882108
]]),
20892109
]),
20902110
CodeBlockNode([
2091-
CodeBlockSpanNode(text: 'four', type: CodeBlockSpanType.text),
2111+
CodeBlockSpanNode(text: 'four', spanTypes: [CodeBlockSpanType.text]),
20922112
]),
20932113
ParagraphNode(wasImplicit: true, links: null, nodes: [TextNode('\n\n')]), // TODO avoid this; it renders wrong
20942114
]]),

0 commit comments

Comments
 (0)