Skip to content

Commit

Permalink
content: Handle code block spans with multiple CSS classes
Browse files Browse the repository at this point in the history
Fixes: zulip#933
  • Loading branch information
rajveermalviya committed Oct 25, 2024
1 parent ce3302e commit 4224f4b
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
16 changes: 12 additions & 4 deletions lib/model/content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1023,17 +1023,25 @@ class _ZulipContentParser {
span = CodeBlockSpanNode(text: text, type: CodeBlockSpanType.text);

case dom.Element(localName: 'span', :final text, :final className):
final CodeBlockSpanType type = codeBlockSpanTypeFromClassName(className);
switch (type) {
case CodeBlockSpanType.unknown:
// Empirically, when a Pygments node has multiple classes, the first
// class names a standard token type and the rest are for non-standard
// token types specific to the language. Zulip web only styles the
// standard token classes and ignores the others, so we do the same.
// See: https://github.com/zulip/zulip-flutter/issues/933
final spanType = className.split(' ')
.map(codeBlockSpanTypeFromClassName)
.firstWhereOrNull((e) => e != CodeBlockSpanType.unknown);

switch (spanType) {
case null:
// TODO(#194): Show these as un-syntax-highlighted code, in production.
return UnimplementedBlockContentNode(htmlNode: divElement);
case CodeBlockSpanType.highlightedLines:
// TODO: Implement nesting in CodeBlockSpanNode to support hierarchically
// inherited styles for `span.hll` nodes.
return UnimplementedBlockContentNode(htmlNode: divElement);
default:
span = CodeBlockSpanNode(text: text, type: type);
span = CodeBlockSpanNode(text: text, type: spanType);
}

default:
Expand Down
18 changes: 18 additions & 0 deletions test/model/content_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,23 @@ class ContentExample {
]),
]);

static const codeBlockSpansWithMultipleClasses = ContentExample(
'code block spans with multiple CSS classes',
'```yaml\n- item\n```',
expectedText: '- item',
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/Greg/near/1949014
'<div class="codehilite" data-code-language="YAML">'
'<pre><span></span><code><span class="p p-Indicator">-</span>'
'<span class="w"> </span>'
'<span class="l l-Scalar l-Scalar-Plain">item</span>\n'
'</code></pre></div>', [
CodeBlockNode([
CodeBlockSpanNode(text: "-", type: CodeBlockSpanType.punctuation),
CodeBlockSpanNode(text: " ", type: CodeBlockSpanType.whitespace),
CodeBlockSpanNode(text: "item", type: CodeBlockSpanType.literal)
]),
]);

// Current servers no longer produce this, but it can be found in ancient
// messages. For example:
// https://chat.zulip.org/#narrow/stream/2-general/topic/Error.20in.20dev.20server/near/18765
Expand Down Expand Up @@ -1160,6 +1177,7 @@ void main() {
testParseExample(ContentExample.codeBlockPlain);
testParseExample(ContentExample.codeBlockHighlightedShort);
testParseExample(ContentExample.codeBlockHighlightedMultiline);
testParseExample(ContentExample.codeBlockSpansWithMultipleClasses);
testParseExample(ContentExample.codeBlockWithEmptyBody);
testParseExample(ContentExample.codeBlockWithHighlightedLines);
testParseExample(ContentExample.codeBlockWithUnknownSpanType);
Expand Down
1 change: 1 addition & 0 deletions test/widgets/content_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ void main() {
testContentSmoke(ContentExample.codeBlockPlain);
testContentSmoke(ContentExample.codeBlockHighlightedShort);
testContentSmoke(ContentExample.codeBlockHighlightedMultiline);
testContentSmoke(ContentExample.codeBlockSpansWithMultipleClasses);

testFontWeight('syntax highlighting: non-bold span',
expectedWght: 400,
Expand Down

0 comments on commit 4224f4b

Please sign in to comment.