cursorController method

void cursorController()

A listener that ensures that the cursor is always outside of a tag.

If the cursor is inside a tag, it is moved to the nearest side, unless the user moved into the tag with the arrow keys, in which case the cursor is moved to the other side.

If a tag is broken, the text between the cursor and the tag is removed.

If a tag is selected, the tag is selected as a whole.

Implementation

void cursorController() {
  final int baseOffset = selection.baseOffset;
  final int extentOffset = selection.extentOffset;
  if (baseOffset == -1) return; // This is sometimes -1; it is unclear why

  // Now, find the positions of all markers. If the cursor is between 1 and 2
  // or 3 and 4, etc., move it out of this range to the nearest side.
  final List<(Match?, Match?)> matchPairs = getTagMatchPairs(text);
  for (int i = 0; i < matchPairs.length; i = i + 1) {
    final (start, end) = matchPairs[i];
    if (start == null && end != null) {
      // A tag has been broken, so remove the text between the cursor and end
      value = TextEditingValue(
        text: text.replaceRange(baseOffset, end.end, ''),
        selection: TextSelection.collapsed(offset: baseOffset),
      );
    } else if (start != null && end == null) {
      // A tag has been broken, so remove the text between the cursor and start
      value = TextEditingValue(
        text: text.replaceRange(start.start, baseOffset, ''),
        selection: TextSelection.collapsed(offset: start.start),
      );
    } else if (start != null && end != null) {
      if (!selection.isCollapsed) {
        // A range is selected, so ensure that the tag is selected as a whole
        if (start.start < baseOffset && baseOffset < end.end) {
          // The baseOffset is within the tag
          if (baseOffset < extentOffset) {
            selection = TextSelection(
              baseOffset: start.start,
              extentOffset: extentOffset,
            );
          } else {
            selection = TextSelection(
              baseOffset: end.end,
              extentOffset: extentOffset,
            );
          }
        } else if (start.start < extentOffset && extentOffset < end.end) {
          // The extentOffset is within the tag
          if (extentOffset < baseOffset) {
            selection = TextSelection(
              baseOffset: start.start,
              extentOffset: baseOffset,
            );
          } else {
            selection =
                TextSelection(baseOffset: end.end, extentOffset: baseOffset);
          }
        }
      } else if (start.start < baseOffset && baseOffset < end.end) {
        // The cursor is within the tag
        if (previousCursorPosition == start.start &&
            baseOffset == (previousCursorPosition + 2)) {
          // The cursor was moved to the right
          selection = TextSelection.collapsed(offset: end.end);
        } else if (previousCursorPosition == end.end &&
            baseOffset == (previousCursorPosition - 2)) {
          // The cursor was moved to the left
          selection = TextSelection.collapsed(offset: start.start);
        } else if ((baseOffset - start.start) < (end.end - baseOffset)) {
          selection = TextSelection.collapsed(offset: start.start);
        } else {
          selection = TextSelection.collapsed(offset: end.end);
        }
      }
    }
  }
}