moveDown function

NavigationResult moveDown(
  1. Root root,
  2. CaretStop current,
  3. double preferredX,
  4. CaretXResolver resolveX,
  5. CaretYResolver resolveY, {
  6. List<CaretStop>? stops,
})

Moves the cursor down by one LogicalLine.

Implementation

NavigationResult moveDown(
  Root root,
  CaretStop current,
  double preferredX,
  CaretXResolver resolveX,
  CaretYResolver resolveY, {
  List<CaretStop>? stops,
}) {
  final stops_ = stops ?? buildAllStops(root);
  if (stops_.isEmpty) return NavigationResult.none;

  final yCache = <CaretStop, double>{};
  double cachedY(CaretStop s) => yCache[s] ??= resolveY(s);
  final xCache = <CaretStop, double>{};
  double cachedX(CaretStop s) => xCache[s] ??= resolveX(s);

  final x = preferredX >= 0.0 ? preferredX : cachedX(current);
  final currentY = cachedY(current);

  print('[MOVE_DOWN] current=${current.fragmentId}:${current.offset} x=$x currentY=$currentY');

  // Find the lowest y that is strictly below the current line
  double? targetY;
  for (final stop in stops_) {
    final y = cachedY(stop);
    if (y > currentY + _kLineYTolerance) {
      if (targetY == null || y < targetY) targetY = y;
    }
  }

  print('[MOVE_DOWN] targetY=$targetY');

  // No line below: go to the last stop of the document
  if (targetY == null) {
    final last = stops_.last;
    if (last == current) return NavigationResult.none;
    print('[MOVE_DOWN] no line below → last=${last.fragmentId}:${last.offset}');
    return NavigationResult(position: last, preferredX: x);
  }

  final lineStops = stops_
      .where((s) => (cachedY(s) - targetY!).abs() <= _kLineYTolerance)
      .toList();

  print('[MOVE_DOWN] lineStops=${lineStops.map((s) => '${s.fragmentId}:${s.offset}').join(', ')}');

  final best = _stopNearestX(lineStops, x, cachedX);
  print('[MOVE_DOWN] best=${best.fragmentId}:${best.offset}');
  return NavigationResult(position: best, preferredX: x);
}