executeHandleDelete function
Handles the Delete key.
Supported behaviors:
- If there's an active selection: delete the selection
- If cursor is at the end of a container: merge with the next node
- If cursor is on an image: remove the image
- If ctrl is pressed: delete the next word
- Otherwise: delete the next character in the fragment
Implementation
bool executeHandleDelete(FluentDocument document, {bool ctrl = false}) {
final root = document.content;
final cursor = document.cursor;
// Case 1: If there's an active selection, delete it
final selection = resolveSelection(
root,
cursor.anchorId,
cursor.anchorOffset,
cursor.focusId,
cursor.focusOffset,
cachedStops: document.caretStops,
cachedLines: document.logicalLines,
);
if (selection != null) {
// Delete the selection by replacing it with an empty string
executeHandleReplaceSelection('', document);
return true;
}
// Case 1.5: If ctrl is pressed, delete the next word
if (ctrl) {
return _handleDeleteNextWord(document);
}
// Find the fragment and the current container
final currentNode = document.nodeById(cursor.anchorId);
if (currentNode is HorizontalRule) {
final targetStop = _findNextStop(
root, cursor.anchorId, 1,
cachedStops: document.caretStops,
cachedLines: document.logicalLines,
);
removeNode(root, currentNode);
if (targetStop != null) {
cursor.moveTo(targetStop.fragmentId, targetStop.offset);
}
document.updateContent();
return true;
}
// Resolve the actual Fragment from the cursor anchor
Fragment? currentFrag;
if (currentNode is Fragment) {
currentFrag = currentNode;
} else if (currentNode is InlineContainerNode) {
final containerNode = currentNode as InlineContainerNode;
final children = containerNode.getChildren();
if (cursor.anchorOffset >= 0 && cursor.anchorOffset < children.length) {
final child = children[cursor.anchorOffset];
if (child is Fragment) currentFrag = child;
}
if (currentFrag == null) {
for (final child in children) {
if (child is Fragment) {
currentFrag = child;
break;
}
}
}
}
if (currentFrag == null) return false;
final container = findLogicalContainer(root, cursor.anchorId);
if (container == null) return false;
// Case 2b: If it's an image, remove the entire node
if (currentFrag is FluentImage) {
final targetStop = _findNextStop(
root, cursor.anchorId, 1,
cachedStops: document.caretStops,
cachedLines: document.logicalLines,
);
removeNode(root, currentFrag);
if (targetStop != null) {
cursor.moveTo(targetStop.fragmentId, targetStop.offset);
}
document.updateContent();
return true;
}
// Case 3: If we're at the end of the fragment
if (cursor.anchorOffset >= currentFrag.text.length) {
return _handleDeleteAtEnd(document, container, currentFrag);
}
// Case 4: Normal character deletion
FragmentOperations.deleteTextInFragment(currentFrag, cursor.anchorOffset, count: 1);
// Update the cursor (stays at the same position)
cursor.moveTo(currentFrag.id, cursor.anchorOffset);
// Notify comment system of the text mutation
if (container is Paragraph) {
final globalOffset = document.getGlobalOffsetInParagraph(
container.id,
currentFrag.id,
cursor.anchorOffset,
);
if (globalOffset != null) {
document.notifyTextMutation(container.id, globalOffset, -1);
}
}
document.updateContent();
return true;
}