applyRule method

  1. @override
Delta? applyRule(
  1. Delta 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(Delta document, int index, {int? len, Object? data, Attribute? attribute}) {
  if (data is! String || !data.contains('\n')) {
    // Only interested in text containing at least one newline character.
    return null;
  }

  final itr = DeltaIterator(document)..skip(index);

  // Look for the next newline.
  final nextNewLine = _getNextNewLine(itr);
  final lineStyle = Style.fromJson(nextNewLine.operation?.attributes ?? <String, dynamic>{});

  final blockStyle = lineStyle.getBlocksExceptHeader();
  // Are we currently in a block? If not then ignore.
  if (blockStyle.isEmpty) {
    return null;
  }

  final resetStyle = <String, dynamic>{};
  // If current line had heading style applied to it we'll need to move this
  // style to the newly inserted line before it and reset style of the
  // original line.
  if (lineStyle.containsKey(Attribute.header.key)) {
    resetStyle.addAll(Attribute.header.toJson());
  }

  // Go over each inserted line and ensure block style is applied.
  final lines = data.split('\n');
  final delta = Delta()..retain(index + (len ?? 0));
  for (var i = 0; i < lines.length; i++) {
    final line = lines[i];
    if (line.isNotEmpty) {
      delta.insert(line);
    }
    if (i == 0) {
      // The first line should inherit the lineStyle entirely.
      delta.insert('\n', lineStyle.toJson());
    } else if (i < lines.length - 1) {
      // we don't want to insert a newline after the last chunk of text, so -1
      final blockAttributes = blockStyle.isEmpty
          ? null
          : blockStyle
              .map<String, dynamic>((_, attribute) => MapEntry<String, dynamic>(attribute.key, attribute.value));
      delta.insert('\n', blockAttributes);
    }
  }

  // Reset style of the original newline character if needed.
  if (resetStyle.isNotEmpty) {
    delta
      ..retain(nextNewLine.skipped!)
      ..retain((nextNewLine.operation!.data as String).indexOf('\n'))
      ..retain(1, resetStyle);
  }

  return delta;
}