backspaceAtAllCursors method
void
backspaceAtAllCursors()
Performs backspace at all cursor positions (primary + secondary).
Implementation
void backspaceAtAllCursors() {
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 delete from bottom to top
final uniqueOffsets = offsets.toSet().toList()
..sort((a, b) => b.compareTo(a));
// Begin compound undo operation
final compound = _undoController?.beginCompoundOperation();
// Running shift tracks how much earlier offsets shifted due to deletions
// processed so far (descending order means no shift needed per-deletion,
// but we need the deleted chars for undo recording).
for (final offset in uniqueOffsets) {
if (offset > 0) {
final deleteStart = (offset - 1).clamp(0, _rope.length);
final deletedChar = _rope.substring(deleteStart, offset);
_rope.delete(deleteStart, offset);
_currentVersion++;
_recordDeletion(
deleteStart,
deletedChar,
selectionBefore,
TextSelection.collapsed(offset: deleteStart),
);
}
}
// End compound so all deletions are one undo unit
compound?.end();
int primaryShift = 0;
for (final o in uniqueOffsets) {
if (o <= primaryOffset && o > 0) {
primaryShift += 1;
}
}
_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 origOffset = sortedAsc[i];
if (origOffset <= 0) continue;
int shift = 0;
for (int j = 0; j <= i; j++) {
if (sortedAsc[j] > 0) shift++;
}
final newOffset = (origOffset - shift).clamp(0, _rope.length);
final primaryNewOffset = (primaryOffset - primaryShift).clamp(
0,
_rope.length,
);
if (newOffset == primaryNewOffset) continue;
final newLine = _rope.getLineAtOffset(newOffset);
final newLineStart = _rope.getLineStartOffset(newLine);
final newChar = newOffset - newLineStart;
_multiCursors.add((line: newLine, character: newChar));
}
multiCursorsChanged = true;
dirtyRegion = TextRange(start: 0, end: _rope.length);
_syncToConnection();
notifyListeners();
}