Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete "sentence" shortcut #32

Merged
merged 7 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/src/core/document/text_delta.dart
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class Delta extends Iterable<TextOperation> {
/// Delete operations have a Number `delete` key defined representing the number of characters to delete.
void delete(int length) => add(TextDelete(length: length));

/// The length of the string fo the [Delta].
/// The length of the string of the [Delta].
@override
int get length {
return _operations.fold(
Expand Down
185 changes: 91 additions & 94 deletions lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ShortcutEventHandler cursorUpSelect = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
final end = _goUp(editorState);
final end = _moveVertical(editorState);
if (end == null) {
return KeyEventResult.ignored;
}
Expand All @@ -55,7 +55,7 @@ ShortcutEventHandler cursorDownSelect = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
final end = _goDown(editorState);
final end = _moveVertical(editorState, upwards: false);
if (end == null) {
return KeyEventResult.ignored;
}
Expand Down Expand Up @@ -191,6 +191,7 @@ ShortcutEventHandler cursorBeginSelect = (editorState, event) {
if (position != null) {
end = position;
}

editorState.service.selectionService.updateSelection(
selection.copyWith(start: start, end: end),
);
Expand Down Expand Up @@ -223,10 +224,12 @@ ShortcutEventHandler cursorUp = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
final upPosition = _goUp(editorState);

final upPosition = _moveVertical(editorState);
editorState.updateCursorSelection(
upPosition == null ? null : Selection.collapsed(upPosition),
);

return KeyEventResult.handled;
};

Expand All @@ -237,10 +240,12 @@ ShortcutEventHandler cursorDown = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
final downPosition = _goDown(editorState);

final downPosition = _moveVertical(editorState, upwards: false);
editorState.updateCursorSelection(
downPosition == null ? null : Selection.collapsed(downPosition),
);

return KeyEventResult.handled;
};

Expand All @@ -251,18 +256,15 @@ ShortcutEventHandler cursorLeft = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
if (selection.isCollapsed) {
final leftPosition = selection.start.goLeft(editorState);
if (leftPosition != null) {
editorState.service.selectionService.updateSelection(
Selection.collapsed(leftPosition),
);
}
} else {
editorState.service.selectionService.updateSelection(
Selection.collapsed(selection.start),
);
}

Position newPosition = selection.isCollapsed
? selection.start.goLeft(editorState) ?? selection.start
: selection.start;

editorState.service.selectionService.updateSelection(
Selection.collapsed(newPosition),
);

return KeyEventResult.handled;
};

Expand All @@ -273,18 +275,15 @@ ShortcutEventHandler cursorRight = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
if (selection.isCollapsed) {
final rightPosition = selection.start.goRight(editorState);
if (rightPosition != null) {
editorState.service.selectionService.updateSelection(
Selection.collapsed(rightPosition),
);
}
} else {
editorState.service.selectionService.updateSelection(
Selection.collapsed(selection.end),
);
}

final newPosition = selection.isCollapsed
? selection.start.goRight(editorState) ?? selection.end
: selection.end;

editorState.service.selectionService.updateSelection(
Selection.collapsed(newPosition),
);

return KeyEventResult.handled;
};

Expand All @@ -294,14 +293,17 @@ ShortcutEventHandler cursorLeftWordSelect = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}

final end =
selection.end.goLeft(editorState, selectionRange: _SelectionRange.word);
if (end == null) {
return KeyEventResult.ignored;
}

editorState.service.selectionService.updateSelection(
selection.copyWith(end: end),
);

return KeyEventResult.handled;
};

Expand All @@ -314,21 +316,13 @@ ShortcutEventHandler cursorLeftWordMove = (editorState, event) {
return KeyEventResult.ignored;
}

if (selection.isCollapsed) {
final leftPosition = selection.start
.goLeft(editorState, selectionRange: _SelectionRange.word);
if (leftPosition != null) {
editorState.service.selectionService.updateSelection(
Selection.collapsed(leftPosition),
);

return KeyEventResult.handled;
}
final newPosition = selection.start
.goLeft(editorState, selectionRange: _SelectionRange.word) ??
selection.start;

editorState.service.selectionService.updateSelection(
Selection.collapsed(selection.start),
);
}
editorState.service.selectionService.updateSelection(
Selection.collapsed(newPosition),
);

return KeyEventResult.handled;
};
Expand All @@ -342,21 +336,13 @@ ShortcutEventHandler cursorRightWordMove = (editorState, event) {
return KeyEventResult.ignored;
}

if (selection.isCollapsed) {
final rightPosition = selection.start
.goRight(editorState, selectionRange: _SelectionRange.word);
if (rightPosition != null) {
editorState.service.selectionService.updateSelection(
Selection.collapsed(rightPosition),
);

return KeyEventResult.handled;
}
final newPosition = selection.start
.goRight(editorState, selectionRange: _SelectionRange.word) ??
selection.end;

editorState.service.selectionService.updateSelection(
Selection.collapsed(selection.end),
);
}
editorState.service.selectionService.updateSelection(
Selection.collapsed(newPosition),
);

return KeyEventResult.handled;
};
Expand All @@ -367,14 +353,17 @@ ShortcutEventHandler cursorRightWordSelect = (editorState, event) {
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}

final end =
selection.end.goRight(editorState, selectionRange: _SelectionRange.word);
if (end == null) {
return KeyEventResult.ignored;
}

editorState.service.selectionService.updateSelection(
selection.copyWith(end: end),
);

return KeyEventResult.handled;
};

Expand Down Expand Up @@ -405,6 +394,30 @@ ShortcutEventHandler cursorLeftWordDelete = (editorState, event) {
return KeyEventResult.handled;
};

ShortcutEventHandler cursorLeftSentenceDelete = (editorState, event) {
final nodes = editorState.service.selectionService.currentSelectedNodes;
final selection = editorState.service.selectionService.currentSelection.value;
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}

if (nodes.length == 1 && nodes.first is TextNode) {
final textNode = nodes.first as TextNode;
if (textNode.toPlainText().isEmpty) {
return KeyEventResult.ignored;
}
}

if (selection.isCollapsed) {
final deleteTransaction = editorState.transaction;
deleteTransaction.deleteText(
nodes.first as TextNode, 0, selection.end.offset);
editorState.apply(deleteTransaction, withUpdateCursor: true);
}

return KeyEventResult.handled;
};

enum _SelectionRange {
character,
word,
Expand Down Expand Up @@ -435,9 +448,9 @@ extension on Position {
path: path,
offset: node.delta.prevRunePosition(offset),
);
} else {
return Position(path: path, offset: offset);
}

return Position(path: path, offset: offset);
case _SelectionRange.word:
if (node is TextNode) {
final result = node.selectable?.getWordBoundaryInPosition(
Expand All @@ -449,11 +462,10 @@ extension on Position {
if (result != null) {
return result.start;
}
} else {
return Position(path: path, offset: offset);
}

return Position(path: path, offset: offset);
}
return null;
}

Position? goRight(
Expand All @@ -464,76 +476,61 @@ extension on Position {
if (node == null) {
return null;
}

final end = node.selectable?.end();
if (end != null && offset >= end.offset) {
final nextStart = node.next?.selectable?.start();
if (nextStart != null) {
return nextStart;
}
return null;
return node.next?.selectable?.start();
}

switch (selectionRange) {
case _SelectionRange.character:
if (node is TextNode) {
return Position(
path: path,
offset: node.delta.nextRunePosition(offset),
);
} else {
return Position(path: path, offset: offset);
}

return Position(path: path, offset: offset);
case _SelectionRange.word:
if (node is TextNode) {
final result = node.selectable?.getWordBoundaryInPosition(this);
if (result != null) {
return result.end;
}
} else {
return Position(path: path, offset: offset);
}

return Position(path: path, offset: offset);
}
return null;
}
}

Position? _goUp(EditorState editorState) {
Position? _moveVertical(
EditorState editorState, {
bool upwards = true,
}) {
final selection = editorState.service.selectionService.currentSelection.value;
final rects = editorState.service.selectionService.selectionRects;
if (rects.isEmpty || selection == null) {
return null;
}
Offset offset;
if (selection.isBackward) {
final rect = rects.reduce(
(current, next) => current.bottom >= next.bottom ? current : next,
);
offset = rect.topRight.translate(0, -rect.height);
} else {
final rect = rects.reduce(
(current, next) => current.top <= next.top ? current : next,
);
offset = rect.topLeft.translate(0, -rect.height);
}
return editorState.service.selectionService.getPositionInOffset(offset);
}

Position? _goDown(EditorState editorState) {
final selection = editorState.service.selectionService.currentSelection.value;
final rects = editorState.service.selectionService.selectionRects;
if (rects.isEmpty || selection == null) {
return null;
}
Offset offset;
if (selection.isBackward) {
final rect = rects.reduce(
(current, next) => current.bottom >= next.bottom ? current : next,
);
offset = rect.bottomRight.translate(0, rect.height);
offset = upwards
? rect.topRight.translate(0, -rect.height)
: rect.bottomRight.translate(0, rect.height);
} else {
final rect = rects.reduce(
(current, next) => current.top <= next.top ? current : next,
);
offset = rect.bottomLeft.translate(0, rect.height);
offset = upwards
? rect.topLeft.translate(0, -rect.height)
: rect.bottomLeft.translate(0, rect.height);
}

return editorState.service.selectionService.getPositionInOffset(offset);
}
9 changes: 8 additions & 1 deletion lib/src/service/shortcut_event/built_in_shortcut_events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,18 @@ List<ShortcutEvent> builtInShortcutEvents = [
),
ShortcutEvent(
key: 'Cursor word delete',
command: 'meta+backspace',
command: 'alt+backspace',
windowsCommand: 'ctrl+backspace',
linuxCommand: 'ctrl+backspace',
handler: cursorLeftWordDelete,
),
ShortcutEvent(
key: 'Cursor sentence delete',
command: 'meta+backspace',
windowsCommand: 'ctrl+alt+backspace',
linuxCommand: 'ctrl+alt+backspace',
handler: cursorLeftSentenceDelete,
),
ShortcutEvent(
key: 'Cursor left select',
command: 'shift+arrow left',
Expand Down
Loading