executeHandleDelete function

bool executeHandleDelete(
  1. FluentDocument document, {
  2. bool ctrl = false,
})

Handles the Delete key.

Supported behaviors:

  1. If there's an active selection: delete the selection
  2. If cursor is at the end of a container: merge with the next node
  3. If cursor is on an image: remove the image
  4. If ctrl is pressed: delete the next word
  5. 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;
}