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