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

Preserve line styles on new line insertion #160

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/parchment/lib/src/heuristics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ class ParchmentHeuristics {
MarkdownBlockShortcutsInsertRule(),
// Lines
PreserveLineStyleOnSplitRule(),
ResetLineFormatOnNewLineRule(),
ResetHeadingFormatOnNewLineRule(),
AutoTextDirectionRule(),
// Inlines
AutoFormatLinksRule(),
PreserveInlineStylesRule(),
// Catch new line
PreserveLineStyleOnNewLineInsertRule(),
// Catch-all
CatchAllInsertRule(),
],
Expand Down
30 changes: 24 additions & 6 deletions packages/parchment/lib/src/heuristics/insert_rules.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ class CatchAllInsertRule extends InsertRule {
}
}

/// Fallback rule for new line which retains line styles
class PreserveLineStyleOnNewLineInsertRule extends InsertRule {
const PreserveLineStyleOnNewLineInsertRule();

@override
Delta? apply(Delta document, int index, Object data) {
if (!isOnlyNewLines(data)) return null;

final iter = DeltaIterator(document);
iter.skip(index);
final nextNewline = _findNextNewline(iter);
if (nextNewline.isEmpty) return null;

return Delta()
..retain(index)
..insert(data, nextNewline.op?.attributes);
}
}

/// Preserves line format when user splits the line into two.
///
/// This rule ignores scenarios when the line is split on its edge, meaning
Expand Down Expand Up @@ -113,13 +132,13 @@ class PreserveLineStyleOnSplitRule extends InsertRule {
}
}

/// Resets format for a newly inserted line when insert occurred at the end
/// of a line (right before a newline).
/// Resets heading format for a newly inserted line when insert occurred at
/// the end of a line (right before a newline).
///
/// This handles scenarios when a new line is added when at the end of a
/// heading line. The newly added line should be a regular paragraph.
class ResetLineFormatOnNewLineRule extends InsertRule {
const ResetLineFormatOnNewLineRule();
class ResetHeadingFormatOnNewLineRule extends InsertRule {
const ResetHeadingFormatOnNewLineRule();

@override
Delta? apply(Delta document, int index, Object data) {
Expand All @@ -144,8 +163,7 @@ class ResetLineFormatOnNewLineRule extends InsertRule {
return Delta()
..retain(index)
..insert('\n', target.attributes)
..retain(1, resetStyle)
..trim();
..retain(1, resetStyle);
}
}
return null;
Expand Down
5 changes: 5 additions & 0 deletions packages/parchment/lib/src/heuristics/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,8 @@ bool isBlockEmbed(Object data) {
}
return false;
}

bool isOnlyNewLines(Object data) {
if (data is! String) return false;
return data.replaceAll('\n', '').isEmpty;
}
25 changes: 23 additions & 2 deletions packages/parchment/test/heuristics/insert_rules_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ void main() {
});
});

group('$PreserveLineStyleOnNewLineInsertRule', () {
final rule = PreserveLineStyleOnNewLineInsertRule();

test('data is not new line only', () {
final doc = Delta()..insert('Test\n');
final actual = rule.apply(doc, 0, '\nOne\n');
expect(actual, isNull);
});

test('preserves line styles', () {
final doc = Delta()
..insert('Test')
..insert('\n', ParchmentAttribute.right.toJson());
final actual = rule.apply(doc, 4, '\n');
final expected = Delta()
..retain(4)
..insert('\n', ParchmentAttribute.right.toJson());
expect(actual, expected);
});
});

group('$PreserveLineStyleOnSplitRule', () {
final rule = PreserveLineStyleOnSplitRule();

Expand Down Expand Up @@ -59,8 +80,8 @@ void main() {
});
});

group('$ResetLineFormatOnNewLineRule', () {
final rule = const ResetLineFormatOnNewLineRule();
group('$ResetHeadingFormatOnNewLineRule', () {
final rule = const ResetHeadingFormatOnNewLineRule();

test('applies when line-break is inserted at the end of line', () {
final doc = Delta()
Expand Down
Loading