Skip to content

Commit

Permalink
feat: implement delete command
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasXu0 committed Jul 7, 2023
1 parent c78dee7 commit cc063e3
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,69 +34,44 @@ CommandShortcutEventHandler _deleteInCollapsedSelection = (editorState) {

final position = selection.start;
final node = editorState.getNodeAtPath(position.path);
if (node == null || node.delta == null) {
final delta = node?.delta;
if (node == null || delta == null) {
return KeyEventResult.ignored;
}

// Why do we use nextRunePosition instead of the position end offset?
// Because some character's length > 1, for example, emoji.
final index = node.delta!.nextRunePosition(position.offset);
final transaction = editorState.transaction;
if (index == node.delta!.length) {
// merge the next node in the current node.
final nextNode = node.next;
if (nextNode == null) {
return KeyEventResult.ignored;
}
//TODO(Lucas): add logic for merging a bulletList or numberedList item.
if (nextNode.next == null && nextNode.children.isEmpty) {
final path = node.path;

// merge the next node with delta
if (position.offset == delta.length) {
final next = node.findDownward((element) => element.delta != null);
if (next != null) {
if (next.children.isNotEmpty) {
final path = node.path + [node.children.length];
transaction.insertNodes(path, next.children);
}
transaction
..mergeText(node, nextNode)
..deleteNode(nextNode)
..afterSelection = Selection.collapsed(
Position(
path: path,
offset: index,
),
..deleteNode(next)
..mergeText(
node,
next,
);
} else {
// merge with the previous node contains delta.
final nextNodeWithDelta =
node.lastNodeWhere((element) => element.delta != null);
if (nextNodeWithDelta != null) {
assert(nextNodeWithDelta.delta != null);
transaction
..mergeText(nextNodeWithDelta, node)
..insertNodes(
// insert children to previous node
nextNodeWithDelta.path.next,
node.children.toList(),
)
..deleteNode(node)
..afterSelection = Selection.collapsed(
Position(
path: nextNodeWithDelta.path,
offset: nextNodeWithDelta.delta!.length,
),
);
} else {
// do nothing if there is no previous node contains delta.
return KeyEventResult.ignored;
}
editorState.apply(transaction);
return KeyEventResult.handled;
}
} else {
// Although the selection may be collapsed,
// its length may not always be equal to 1 because some characters have a length greater than 1.
transaction.deleteText(
node,
position.offset,
index - position.offset,
);
final nextIndex = delta.nextRunePosition(position.offset);
if (nextIndex <= delta.length) {
transaction.deleteText(
node,
position.offset,
nextIndex - position.offset,
);
editorState.apply(transaction);
return KeyEventResult.handled;
}
}

editorState.apply(transaction);
return KeyEventResult.handled;
return KeyEventResult.ignored;
};

/// Handle delete key event when selection is not collapsed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ CommandShortcutEventHandler _selectAllCommandHandler = (editorState) {
)
?.selectable;
final lastSelectable = editorState.document.root
.lastNodeWhere(
.lastChildWhere(
(element) => element.selectable != null,
)
?.selectable;
Expand Down
30 changes: 27 additions & 3 deletions lib/src/extensions/node_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extension NodeExtensions on Node {
Node? previousNodeWhere(bool Function(Node element) test) {
var previous = this.previous;
while (previous != null) {
final last = previous.lastNodeWhere(test);
final last = previous.lastChildWhere(test);
if (last != null) {
return last;
}
Expand All @@ -49,11 +49,11 @@ extension NodeExtensions on Node {
}

/// Returns the last node in the subtree that satisfies the given predicate
Node? lastNodeWhere(bool Function(Node element) test) {
Node? lastChildWhere(bool Function(Node element) test) {
final children = this.children.toList().reversed;
for (final child in children) {
if (child.children.isNotEmpty) {
final last = child.lastNodeWhere(test);
final last = child.lastChildWhere(test);
if (last != null) {
return last;
}
Expand All @@ -65,6 +65,30 @@ extension NodeExtensions on Node {
return null;
}

// find the node from it's children or it's next sibling to find the node that matches the given predicate
Node? findDownward(bool Function(Node element) test) {
final children = this.children.toList();
for (final child in children) {
if (test(child)) {
return child;
}
if (child.children.isNotEmpty) {
final node = child.findDownward(test);
if (node != null) {
return node;
}
}
}
final next = this.next;
if (next != null) {
if (test(next)) {
return next;
}
return next.findDownward(test);
}
return null;
}

bool allSatisfyInSelection(
Selection selection,
bool Function(Delta delta) test,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,12 @@ void main() async {
final delta = Delta()..insert(text);
final editor = tester.editor
..addNode(headingNode(level: 1, delta: delta))
..addNode(bulletedListNode(
delta: delta,
children: [bulletedListNode(delta: delta)],
));
..addNode(
bulletedListNode(
delta: delta,
children: [bulletedListNode(delta: delta)],
),
);

await editor.startTesting();

Expand Down Expand Up @@ -374,10 +376,12 @@ void main() async {
final delta = Delta()..insert(text);
final editor = tester.editor
..addNode(bulletedListNode(delta: delta))
..addNode(bulletedListNode(
delta: delta,
children: [bulletedListNode(delta: delta)],
));
..addNode(
bulletedListNode(
delta: delta,
children: [bulletedListNode(delta: delta)],
),
);

await editor.startTesting();

Expand Down

0 comments on commit cc063e3

Please sign in to comment.