insertAtAllCursors method

void insertAtAllCursors(
  1. String textToInsert
)

Inserts textToInsert at all cursor positions (primary + secondary).

Insertions are performed from the last (highest-offset) cursor to the first so that earlier offsets are not invalidated by later insertions. After insertion, all cursor positions are updated to sit after the inserted text.

Implementation

void insertAtAllCursors(String textToInsert) {
  if (readOnly || _multiCursors.isEmpty) {
    return;
  }

  _flushBuffer();

  final selectionBefore = _selection;
  final primaryOffset = selection.extentOffset.clamp(0, _rope.length);
  final offsets = <int>[primaryOffset];
  for (final c in _multiCursors) {
    offsets.add(_multiCursorToOffset(c).clamp(0, _rope.length));
  }

  // Sort descending so we insert from bottom to top
  final uniqueOffsets = offsets.toSet().toList()
    ..sort((a, b) => b.compareTo(a));

  // Begin compound undo operation
  final compound = _undoController?.beginCompoundOperation();

  for (final offset in uniqueOffsets) {
    final safeOffset = offset.clamp(0, _rope.length);
    _rope.insert(safeOffset, textToInsert);
    _currentVersion++;

    _recordInsertion(
      safeOffset,
      textToInsert,
      selectionBefore,
      TextSelection.collapsed(offset: safeOffset + textToInsert.length),
    );
  }

  // End compound so all insertions are one undo unit
  compound?.end();

  int primaryShift = 0;
  for (final o in uniqueOffsets) {
    if (o <= primaryOffset) {
      primaryShift += textToInsert.length;
    }
  }
  _selection = TextSelection.collapsed(
    offset: (primaryOffset + primaryShift).clamp(0, _rope.length),
  );

  _multiCursors.clear();
  final sortedAsc = uniqueOffsets.reversed.toList();
  for (int i = 0; i < sortedAsc.length; i++) {
    final newOffset = sortedAsc[i] + (i + 1) * textToInsert.length;
    final safeNewOffset = newOffset.clamp(0, _rope.length);
    final newLine = _rope.getLineAtOffset(safeNewOffset);
    final newLineStart = _rope.getLineStartOffset(newLine);
    final newChar = safeNewOffset - newLineStart;
    final primaryNewOffset = primaryOffset + primaryShift;

    if (safeNewOffset == primaryNewOffset) continue;
    _multiCursors.add((line: newLine, character: newChar));
  }

  multiCursorsChanged = true;
  dirtyRegion = TextRange(start: 0, end: _rope.length);
  _syncToConnection();
  notifyListeners();
}