buildModelOffsets function

BlockOffsetMap buildModelOffsets(
  1. ElementNode block
)

Builds block's flat text and offset map from the model alone.

Deliberately distinct from the map the renderer produces alongside a span. That one describes what is on screen, case transforms included; this one describes what the user is editing. Handing a presentational STRASSE to an input method would have it autocorrect, select and replace text that does not exist in the document.

Because nothing here is presentational, every segment is one-to-one, and offsets map without the edge cases OffsetSegment.isIdentity guards.

Implementation

BlockOffsetMap buildModelOffsets(ElementNode block) {
  final segments = <OffsetSegment>[];
  final buffer = StringBuffer();

  void visit(ElementNode parent) {
    var index = 0;
    for (final child in parent.children) {
      switch (child) {
        case final TextNode text:
          final content = text.getTextContent();
          segments.add(
            OffsetSegment(
              key: text.key,
              flatStart: buffer.length,
              flatLength: content.length,
              modelLength: content.length,
              type: PointType.text,
              parent: parent.key,
              indexInParent: index,
            ),
          );
          buffer.write(content);
        case final LineBreakNode lineBreak:
          segments.add(
            OffsetSegment(
              key: lineBreak.key,
              flatStart: buffer.length,
              flatLength: 1,
              modelLength: 1,
              type: PointType.element,
              parent: parent.key,
              indexInParent: index,
            ),
          );
          buffer.write('\n');
        case final DecoratorNode decorator when decorator.isInline:
          segments.add(
            OffsetSegment(
              key: decorator.key,
              flatStart: buffer.length,
              flatLength: 1,
              modelLength: 1,
              type: PointType.element,
              parent: parent.key,
              indexInParent: index,
            ),
          );
          buffer.write('');
        case final ElementNode inline when inline.isInline:
          visit(inline);
        default:
          break;
      }
      index++;
    }
  }

  visit(block);
  return BlockOffsetMap(
    blockKey: block.key,
    flatText: buffer.toString(),
    segments: segments,
  );
}