applyRule method

  1. @override
Delta? applyRule(
  1. Document document,
  2. int index, {
  3. int? len,
  4. Object? data,
  5. Attribute? attribute,
})
override

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;
}