applyRule method
Applies heuristic rule to an operation on a document
and returns
resulting Delta.
Implementation
@override
Delta? applyRule(Document document, int index,
{int? len, Object? data, Attribute? attribute}) {
final itr = DeltaIterator(document.toDelta())..skip(index);
var op = itr.next(1);
if (op.data != '\n') {
return null;
}
final isNotPlain = op.isNotPlain;
final attrs = op.attributes;
itr.skip(len! - 1);
if (!itr.hasNext) {
// User attempts to delete the last newline character, prevent it.
return Delta()
..retain(index)
..delete(len - 1);
}
final delta = Delta()
..retain(index)
..delete(len);
// Check if the previous line is empty
final prevItr = DeltaIterator(document.toDelta())..skip(index - 1);
final prevOp = prevItr.next(1);
if (prevOp.data == '\n') {
// Check if the current block is at the start and not empty
final currentBlockItr = DeltaIterator(document.toDelta())..skip(index);
var currentBlockOp = currentBlockItr.next(1);
final isBlockStart = currentBlockOp.data == '\n';
var isBlockNotEmpty = false;
while (currentBlockItr.hasNext) {
currentBlockOp = currentBlockItr.next();
if (currentBlockOp.data is String &&
(currentBlockOp.data as String).contains('\n')) {
break;
}
if (currentBlockOp.data is String &&
(currentBlockOp.data as String).trim().isNotEmpty) {
isBlockNotEmpty = true;
}
}
if (isBlockStart && isBlockNotEmpty) {
// Previous line is empty, skip the merge
return delta;
}
}
while (itr.hasNext) {
op = itr.next();
final text = op.data is String ? (op.data as String?)! : '';
final lineBreak = text.indexOf('\n');
if (lineBreak == -1) {
delta.retain(op.length!);
continue;
}
var attributes = op.attributes?.map<String, dynamic>(
(key, dynamic value) => MapEntry<String, dynamic>(key, null));
if (isNotPlain) {
attributes ??= <String, dynamic>{};
attributes.addAll(attrs!);
}
delta
..retain(lineBreak)
..retain(1, attributes);
break;
}
return delta;
}