Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle unsupported attributes in Markdown conversion + horizontal lines #418

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
8 changes: 5 additions & 3 deletions packages/fleather/lib/src/widgets/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@
}

/// The data from the closest [FleatherTheme] instance that encloses the given
/// context.
/// [context].
///
/// Returns `null` if there is no [FleatherTheme] in the given build context
/// and [nullOk] is set to `true`. If [nullOk] is set to `false` (default)
/// then this method asserts.
static FleatherThemeData? of(BuildContext context, {bool nullOk = false}) {
final widget = context.dependOnInheritedWidgetOfExactType<FleatherTheme>();
if (widget == null && nullOk) return null;
assert(widget != null,
'$FleatherTheme.of() called with a context that does not contain a FleatherTheme.');
assert(
widget != null,
'${FleatherTheme.of} called with a context that does not contain a $FleatherTheme.',

Check warning on line 42 in packages/fleather/lib/src/widgets/theme.dart

View check run for this annotation

Codecov / codecov/patch

packages/fleather/lib/src/widgets/theme.dart#L42

Added line #L42 was not covered by tests
);
return widget!.data;
}
}
Expand Down
8 changes: 6 additions & 2 deletions packages/parchment/lib/codecs.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
/// Provides codecs to convert Parchment documents to other formats.
library parchment.codecs;

import 'src/codecs/markdown.dart';
import 'src/codecs/html.dart';
import 'src/codecs/markdown.dart';

export 'src/codecs/markdown.dart';
export 'src/codecs/html.dart';
export 'src/codecs/markdown.dart';

/// Markdown codec for Parchment documents.
const parchmentMarkdown = ParchmentMarkdownCodec();

/// Not strict markdown codec for Parchment documents.
const parchmentMarkdownNotStrict =
ParchmentMarkdownCodec(strictEncoding: false);

/// HTML codec for Parchment documents.
const parchmentHtml = ParchmentHtmlCodec();
67 changes: 54 additions & 13 deletions packages/parchment/lib/src/codecs/markdown.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import 'dart:convert';

import 'package:parchment_delta/parchment_delta.dart';

import '../document.dart';
import '../document/attributes.dart';
import '../document/block.dart';
import '../document/leaf.dart';
import '../document/line.dart';
import '../../parchment.dart';

class ParchmentMarkdownCodec extends Codec<ParchmentDocument, String> {
const ParchmentMarkdownCodec();
const ParchmentMarkdownCodec({this.strictEncoding = true});

maelchiotti marked this conversation as resolved.
Show resolved Hide resolved
/// Whether to strictly stick to the Markdown syntax during the encoding.
///
/// If this option is enabled, during the encoding, if attributes that are
/// not natively supported by the Markdown syntax exist, an exception will be
/// thrown. Otherwise, they will be converted in the best way possible
/// (for example with HTML tags, plain text or placeholders).
///
/// Currently supported attributes:
/// - Underline with `<u>...</u>`
final bool strictEncoding;

@override
Converter<String, ParchmentDocument> get decoder =>
_ParchmentMarkdownDecoder();

@override
Converter<ParchmentDocument, String> get encoder =>
_ParchmentMarkdownEncoder();
_ParchmentMarkdownEncoder(strict: strictEncoding);
}

class _ParchmentMarkdownDecoder extends Converter<String, ParchmentDocument> {
Expand Down Expand Up @@ -354,6 +359,10 @@
}

class _ParchmentMarkdownEncoder extends Converter<ParchmentDocument, String> {
const _ParchmentMarkdownEncoder({required this.strict});

final bool strict;

static final simpleBlocks = <ParchmentAttribute, String>{
ParchmentAttribute.bq: '> ',
ParchmentAttribute.ul: '* ',
Expand Down Expand Up @@ -403,7 +412,16 @@
ParchmentAttribute? currentBlockAttribute;

void handleLine(LineNode node) {
if (node.hasBlockEmbed) return;
if (node.hasBlockEmbed) {
if ((node.children.single as EmbedNode).value ==
BlockEmbed.horizontalRule) {
_writeHorizontalLineTag(buffer);

Check warning on line 418 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L416-L418

Added lines #L416 - L418 were not covered by tests
} else {
buffer.write('[object]');

Check warning on line 420 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L420

Added line #L420 was not covered by tests
}

return;
}

for (final attr in node.style.lineAttributes) {
if (attr.key == ParchmentAttribute.block.key) {
Expand Down Expand Up @@ -508,8 +526,12 @@
// no-op already handled in handleBlock
} else if (attribute?.key == ParchmentAttribute.indent.key) {
// no-op already handled in handleBlock
} else {
} else if (!strict && attribute?.key == ParchmentAttribute.underline.key) {
_writeUnderlineTag(buffer, close: close);
} else if (strict) {

Check warning on line 531 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L531

Added line #L531 was not covered by tests
throw ArgumentError('Cannot handle $attribute');
} else {
_writeObjectTag(buffer);

Check warning on line 534 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L534

Added line #L534 was not covered by tests
}
}

Expand All @@ -521,6 +543,14 @@
buffer.write('_');
}

void _writeUnderlineTag(StringBuffer buffer, {bool close = false}) {
if (close) {
buffer.write('</u>');
} else {
buffer.write('<u>');
}
}

void _writeInlineCodeTag(StringBuffer buffer) {
buffer.write('`');
}
Expand All @@ -529,8 +559,11 @@
buffer.write('~~');
}

void _writeLinkTag(StringBuffer buffer, ParchmentAttribute<String> link,
{bool close = false}) {
void _writeLinkTag(
maelchiotti marked this conversation as resolved.
Show resolved Hide resolved
StringBuffer buffer,
ParchmentAttribute<String> link, {
bool close = false,
}) {
if (close) {
buffer.write('](${link.value})');
} else {
Expand Down Expand Up @@ -560,4 +593,12 @@
}
}
}

void _writeHorizontalLineTag(StringBuffer buffer) {
buffer.write('---');

Check warning on line 598 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L597-L598

Added lines #L597 - L598 were not covered by tests
}

void _writeObjectTag(StringBuffer buffer) {
buffer.write('[object]');

Check warning on line 602 in packages/parchment/lib/src/codecs/markdown.dart

View check run for this annotation

Codecov / codecov/patch

packages/parchment/lib/src/codecs/markdown.dart#L601-L602

Added lines #L601 - L602 were not covered by tests
}
}
14 changes: 14 additions & 0 deletions packages/parchment/test/codecs/markdown_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ void main() {
runFor('~~strike through~~\n\n', true);
});

test('underline', () {
final delta = Delta()
..insert('an ')
..insert('underlined', ParchmentAttribute.underline.toJson())
..insert(' text')
..insert('\n');

final result =
parchmentMarkdownNotStrict.encode(ParchmentDocument.fromDelta(delta));
final expected = 'an <u>underlined</u> text\n\n';

expect(result, expected);
});

test('intersecting inline styles', () {
final markdown = 'This **house _is a_ circus**\n\n';
final document = parchmentMarkdown.decode(markdown);
Expand Down
Loading