moveCursor method
void
moveCursor(
- SelectionMoveDirection direction, [
- SelectionMoveRange range = SelectionMoveRange.character
Implementation
void moveCursor(
SelectionMoveDirection direction, [
SelectionMoveRange range = SelectionMoveRange.character,
]) {
final selection = this.selection?.normalized;
if (selection == null) {
return;
}
// If the selection is not collapsed, then we want to collapse the selection
if (!selection.isCollapsed && range != SelectionMoveRange.line) {
// move the cursor to the start or end of the selection
this.selection = selection.collapse(
atStart: direction == SelectionMoveDirection.forward,
);
return;
}
final node = getNodeAtPath(selection.start.path);
if (node == null) {
return;
}
// Originally, I want to make this function as pure as possible,
// but I have to import the selectable here to compute the selection.
final start = node.selectable?.start();
final end = node.selectable?.end();
final offset = direction == SelectionMoveDirection.forward
? selection.startIndex
: selection.endIndex;
{
// the cursor is at the start of the node
// move the cursor to the end of the previous node
if (direction == SelectionMoveDirection.forward &&
start != null &&
start.offset >= offset) {
final previousEnd = node
.previousNodeWhere((element) => element.selectable != null)
?.selectable
?.end();
if (previousEnd != null) {
updateSelectionWithReason(
Selection.collapsed(previousEnd),
reason: SelectionUpdateReason.uiEvent,
);
}
return;
}
// the cursor is at the end of the node
// move the cursor to the start of the next node
else if (direction == SelectionMoveDirection.backward &&
end != null &&
end.offset <= offset) {
final nextStart = node.next?.selectable?.start();
if (nextStart != null) {
updateSelectionWithReason(
Selection.collapsed(nextStart),
reason: SelectionUpdateReason.uiEvent,
);
}
return;
}
}
final delta = node.delta;
switch (range) {
case SelectionMoveRange.character:
if (delta != null) {
// move the cursor to the left or right by one character
updateSelectionWithReason(
Selection.collapsed(
selection.start.copyWith(
offset: direction == SelectionMoveDirection.forward
? delta.prevRunePosition(offset)
: delta.nextRunePosition(offset),
),
),
reason: SelectionUpdateReason.uiEvent,
);
} else {
throw UnimplementedError();
}
break;
case SelectionMoveRange.word:
final delta = node.delta;
if (delta != null) {
final position = direction == SelectionMoveDirection.forward
? Position(
path: node.path,
offset: delta.prevRunePosition(offset),
)
: selection.start;
// move the cursor to the left or right by one line
final wordSelection =
node.selectable?.getWordBoundaryInPosition(position);
if (wordSelection != null) {
updateSelectionWithReason(
Selection.collapsed(
direction == SelectionMoveDirection.forward
? wordSelection.start
: wordSelection.end,
),
reason: SelectionUpdateReason.uiEvent,
);
}
} else {
throw UnimplementedError();
}
break;
case SelectionMoveRange.line:
if (delta != null) {
// move the cursor to the left or right by one line
updateSelectionWithReason(
Selection.collapsed(
selection.start.copyWith(
offset: direction == SelectionMoveDirection.forward
? 0
: delta.length,
),
),
reason: SelectionUpdateReason.uiEvent,
);
} else {
throw UnimplementedError();
}
break;
default:
throw UnimplementedError();
}
}