From f9a1cb26233eeb7d80a6354913dc68ed279d2975 Mon Sep 17 00:00:00 2001 From: Mihir <84044317+squidrye@users.noreply.github.com> Date: Mon, 27 Mar 2023 07:50:01 +0530 Subject: [PATCH] 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 bcc014e84d09633ee14d5090f06e609fa95af481. * 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 --- .../lib/src/core/transform/transaction.dart | 45 ++++++++++++++++--- .../test/core/transform/transaction_test.dart | 39 +++++++++++++++- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart index 15bce2a6b7..6c369f566e 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart @@ -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))); } } } diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/test/core/transform/transaction_test.dart b/frontend/appflowy_flutter/packages/appflowy_editor/test/core/transform/transaction_test.dart index 8aa53dcabc..bfb9fa2b3a 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/test/core/transform/transaction_test.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/test/core/transform/transaction_test.dart @@ -125,7 +125,7 @@ void main() async { .map((e) => editor.nodeAtPath([e])!) .whereType() .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() + .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() + .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!'); + }); }); }