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));
  }

  final uniqueOffsets = offsets.toSet().toList()
    ..sort((a, b) => b.compareTo(a));

  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),
    );
  }

  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();
}