parseDeltaToSpans static method

List<InlineSpan> parseDeltaToSpans({
  1. MentionConfig? mentionConfig,
  2. EmojiConfig? emojiConfig,
  3. required Delta delta,
  4. TextStyle? baseStyle,
  5. void onMentionSelectedAsDelta(
    1. Delta
    )?,
  6. bool applyBlockPrefixes = false,
  7. TextSelection? selectionRange,
  8. Color? selectionColor,
  9. void onLinkTap(
    1. String url
    )?,
})

Implementation

static List<InlineSpan> parseDeltaToSpans({
  MentionConfig? mentionConfig,
  EmojiConfig? emojiConfig,
  required Delta delta,
  TextStyle? baseStyle,
  void Function(Delta)? onMentionSelectedAsDelta,
  bool applyBlockPrefixes = false,
  TextSelection? selectionRange,
  Color? selectionColor,
  void Function(String url)? onLinkTap,
}) {
  final spans = <InlineSpan>[];
  var currentOffset = 0;
  final ops = delta.toJson() as List<dynamic>;

  if (!applyBlockPrefixes) {
    for (var i = 0; i < ops.length; i++) {
      final op = ops[i];
      var insert = op['insert'];
      if (insert == null) continue;

      final attr = op['attributes'] as Map<String, dynamic>?;

      if (i == ops.length - 1 && insert is String) {
        if (insert.endsWith('\n')) {
          insert = insert.substring(0, insert.length - 1);
        }

        if (insert.isEmpty && attr == null && spans.isNotEmpty) {
          continue;
        }
      }

      final generated = _opToSpans(
        mentionConfig: mentionConfig,
        emojiConfig: emojiConfig,
        insert: insert,
        attributes: attr,
        baseStyle: baseStyle,
        offset: currentOffset,
        selection: selectionRange,
        selectionColor: selectionColor,
        onMentionSelected: onMentionSelectedAsDelta,
        onLinkTap: onLinkTap,
      );

      spans.addAll(generated);
      currentOffset += insert is String ? insert.length : 1;
    }

    return spans;
  }

  final lines = <({List<dynamic> ops, Map<String, dynamic>? blockAttr})>[];
  var lineOps = <dynamic>[];

  for (final op in ops) {
    final insert = op['insert'];
    final attr = op['attributes'] as Map<String, dynamic>?;

    if (insert is String) {
      final parts = insert.split('\n');
      for (var i = 0; i < parts.length; i++) {
        if (parts[i].isNotEmpty) {
          lineOps.add({'insert': parts[i], 'attributes': attr});
        }
        if (i < parts.length - 1) {
          lines.add((ops: List.from(lineOps), blockAttr: attr));
          lineOps = [];
        }
      }
    } else {
      lineOps.add(op);
    }
  }
  if (lineOps.isNotEmpty) {
    lines.add((ops: lineOps, blockAttr: null));
  }

  if (lines.isNotEmpty && lines.last.ops.isEmpty && lines.last.blockAttr == null) {
    lines.removeLast();
  }

  var orderedCounter = 0;
  for (var lineIdx = 0; lineIdx < lines.length; lineIdx++) {
    final line = lines[lineIdx];
    final blockAttr = line.blockAttr;
    final isOrdered = blockAttr?['list'] == 'ordered';

    if (isOrdered) {
      final realIndex = blockAttr?['list-real-index'] as int?;
      if (realIndex != null) {
        orderedCounter = realIndex;
      } else {
        // Fallback: индекс не задан явно — продолжаем автонумерацию.
        orderedCounter++;
      }
    } else if (blockAttr?['list'] == null) {
      orderedCounter = 0;
    }

    if (lineIdx > 0) {
      spans.add(TextSpan(text: '\n', style: baseStyle));
      currentOffset += 1;
    }

    for (var i = 0; i < line.ops.length; i++) {
      final op = line.ops[i];
      final insert = op['insert'];
      final attr = op['attributes'] as Map<String, dynamic>?;

      if (i == 0 && insert is String && blockAttr != null) {
        final prefix = isOrdered ? '$orderedCounter. ' : blockAttr.blockPrefixInfo.$1;
        if (prefix.isNotEmpty) {
          spans.add(TextSpan(text: prefix, style: baseStyle));
          currentOffset += prefix.length;
        }
      }

      final generated = _opToSpans(
        mentionConfig: mentionConfig,
        emojiConfig: emojiConfig,
        insert: insert,
        attributes: attr,
        baseStyle: baseStyle,
        offset: currentOffset,
        selection: selectionRange,
        selectionColor: selectionColor,
        onMentionSelected: onMentionSelectedAsDelta,
        onLinkTap: onLinkTap,
      );
      spans.addAll(generated);
      currentOffset += insert is String ? insert.length : 1;
    }
  }
  return spans;
}