collectInlineTapRuns function

List<InlineTapRun> collectInlineTapRuns(
  1. InlineSpan root
)

Every TappableTextSpan in root, as plain-text ranges.

Measured after the subtree, so a span built over TextSpan.children covers everything inside it rather than its own (absent) text — the reason a wrapper is a working tap target here and a dead one with a recognizer. Offsets count a placeholder as the single U+FFFC code unit the engine lays out, so they line up with RenderParagraph.getBoxesForSelection.

Identical in shape to collectInlineCodeRuns.

Implementation

List<InlineTapRun> collectInlineTapRuns(InlineSpan root) {
  final runs = <InlineTapRun>[];
  var offset = 0;

  void visit(InlineSpan span) {
    if (span is TextSpan) {
      final start = offset;
      offset += span.text?.length ?? 0;
      final children = span.children;
      if (children != null) {
        for (final child in children) {
          visit(child);
        }
      }
      if (span is TappableTextSpan && offset > start) {
        runs.add(
          InlineTapRun(
            start: start,
            end: offset,
            onTap: span.onTap,
            hoverStyle: span.hoverStyle,
          ),
        );
      }
    } else if (span is PlaceholderSpan) {
      offset += 1;
    } else {
      offset += span.toPlainText(includePlaceholders: true).length;
    }
  }

  visit(root);
  return runs;
}