fix: open-ai replace does not work in certain use-cases (#2100)

* test: added test to verify correct ordering after replacement of multiline text-nodes

* fix: open-ai replace does not work on certain use-cases

* refactor: using predefined operation insert node to create new nodes.

* Revert "refactor: using predefined operation insert node to create new nodes."

This reverts commit bcc014e84d.

* refactor: using predefined operation insert node to create new nodes.

* fix: open-ai replace does not work in certain use-cases

* fix: fixed logic and tests for replacement of larger textNodes with smaller text.

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
Mihir 2023-03-27 07:50:01 +05:30 committed by GitHub
parent 1536cdd15a
commit f9a1cb2623
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 8 deletions

View File

@ -363,6 +363,19 @@ extension TextTransaction on Transaction {
);
} else {
deleteNode(textNode);
if (i == textNodes.length - 1) {
final delta = Delta()
..insert(texts[0])
..addAll(
textNodes.last.delta.slice(selection.end.offset),
);
replaceText(
textNode,
selection.start.offset,
texts[0].length,
delta.toPlainText(),
);
}
}
}
afterSelection = null;
@ -371,6 +384,8 @@ extension TextTransaction on Transaction {
if (textNodes.length < texts.length) {
final length = texts.length;
var path = textNodes.first.path;
for (var i = 0; i < texts.length; i++) {
final text = texts[i];
if (i == 0) {
@ -380,13 +395,15 @@ extension TextTransaction on Transaction {
textNodes.first.toPlainText().length,
text,
);
} else if (i == length - 1) {
path = path.next;
} else if (i == length - 1 && textNodes.length >= 2) {
replaceText(
textNodes.last,
0,
selection.endIndex,
text,
);
path = path.next;
} else {
if (i < textNodes.length - 1) {
replaceText(
@ -395,14 +412,28 @@ extension TextTransaction on Transaction {
textNodes[i].toPlainText().length,
text,
);
path = path.next;
} else {
var path = textNodes.first.path;
var j = i - textNodes.length + length - 1;
while (j > 0) {
path = path.next;
j--;
if (i == texts.length - 1) {
final delta = Delta()
..insert(text)
..addAll(
textNodes.last.delta.slice(selection.end.offset),
);
insertNode(
path,
TextNode(
delta: delta,
),
);
} else {
insertNode(
path,
TextNode(
delta: Delta()..insert(text),
),
);
}
insertNode(path, TextNode(delta: Delta()..insert(text)));
}
}
}

View File

@ -125,7 +125,7 @@ void main() async {
.map((e) => editor.nodeAtPath([e])!)
.whereType<TextNode>()
.toList(growable: false);
expect(textNodes[0].toPlainText(), '0123ABC');
expect(textNodes[0].toPlainText(), '0123ABC456789');
});
testWidgets('test replaceTexts, textNodes.length < texts.length',
@ -165,5 +165,42 @@ void main() async {
expect(textNodes[2].toPlainText(), 'ABC');
expect(textNodes[3].toPlainText(), 'ABC456789');
});
testWidgets('test replaceTexts, textNodes.length << texts.length',
(tester) async {
TestWidgetsFlutterBinding.ensureInitialized();
final editor = tester.editor..insertTextNode('Welcome to AppFlowy!');
await editor.startTesting();
await tester.pumpAndSettle();
expect(editor.documentLength, 1);
// select 'to'
final selection = Selection(
start: Position(path: [0], offset: 8),
end: Position(path: [0], offset: 10),
);
final transaction = editor.editorState.transaction;
var textNodes = [0]
.map((e) => editor.nodeAtPath([e])!)
.whereType<TextNode>()
.toList(growable: false);
final texts = ['ABC1', 'ABC2', 'ABC3', 'ABC4', 'ABC5'];
transaction.replaceTexts(textNodes, selection, texts);
editor.editorState.apply(transaction);
await tester.pumpAndSettle();
expect(editor.documentLength, 5);
textNodes = [0, 1, 2, 3, 4]
.map((e) => editor.nodeAtPath([e])!)
.whereType<TextNode>()
.toList(growable: false);
expect(textNodes[0].toPlainText(), 'Welcome ABC1');
expect(textNodes[1].toPlainText(), 'ABC2');
expect(textNodes[2].toPlainText(), 'ABC3');
expect(textNodes[3].toPlainText(), 'ABC4');
expect(textNodes[4].toPlainText(), 'ABC5 AppFlowy!');
});
});
}