From 45556ae015a703b16afb0e9ae536611cd9511b85 Mon Sep 17 00:00:00 2001 From: Vincent Chan Date: Wed, 10 Aug 2022 17:00:04 +0800 Subject: [PATCH] refactor: flutter style optional chaining --- .../lib/src/document/text_delta.dart | 46 ++-- .../src/operation/transaction_builder.dart | 27 +- .../copy_paste_handler.dart | 42 +-- .../flowy_editor/test/delta_test.dart | 255 +++++++++++------- 4 files changed, 217 insertions(+), 153 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart index c886f9d5c8..6626ba7a86 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart @@ -276,14 +276,13 @@ class Delta extends Iterable { Delta([List? ops]) : _operations = ops ?? []; - Delta addAll(Iterable textOps) { + void addAll(Iterable textOps) { textOps.forEach(add); - return this; } - Delta add(TextOperation textOp) { + void add(TextOperation textOp) { if (textOp.isEmpty) { - return this; + return; } _rawString = null; @@ -291,12 +290,12 @@ class Delta extends Iterable { final lastOp = _operations.last; if (lastOp is TextDelete && textOp is TextDelete) { lastOp.length += textOp.length; - return this; + return; } if (mapEquals(lastOp.attributes, textOp.attributes)) { if (lastOp is TextInsert && textOp is TextInsert) { lastOp.content += textOp.content; - return this; + return; } // if there is an delete before the insert // swap the order @@ -304,17 +303,16 @@ class Delta extends Iterable { _operations.removeLast(); _operations.add(textOp); _operations.add(lastOp); - return this; + return; } if (lastOp is TextRetain && textOp is TextRetain) { lastOp.length += textOp.length; - return this; + return; } } } _operations.add(textOp); - return this; } Delta slice(int start, [int? end]) { @@ -337,20 +335,13 @@ class Delta extends Iterable { return result; } - Delta insert(String content, [Attributes? attributes]) { - final op = TextInsert(content, attributes); - return add(op); - } + void insert(String content, [Attributes? attributes]) => + add(TextInsert(content, attributes)); - Delta retain(int length, [Attributes? attributes]) { - final op = TextRetain(length, attributes); - return add(op); - } + void retain(int length, [Attributes? attributes]) => + add(TextRetain(length, attributes)); - Delta delete(int length) { - final op = TextDelete(length); - return add(op); - } + void delete(int length) => add(TextDelete(length)); int get length { return _operations.fold( @@ -409,7 +400,7 @@ class Delta extends Iterable { if (!otherIter.hasNext && delta._operations[delta._operations.length - 1] == newOp) { final rest = Delta(thisIter.rest()); - return delta.concat(rest).chop(); + return (delta + rest)..chop(); } } else if (otherOp is TextDelete && (thisOp is TextRetain)) { delta.add(otherOp); @@ -417,10 +408,10 @@ class Delta extends Iterable { } } - return delta.chop(); + return delta..chop(); } - Delta concat(Delta other) { + Delta operator +(Delta other) { var ops = [..._operations]; if (other._operations.isNotEmpty) { ops.add(other._operations[0]); @@ -429,16 +420,15 @@ class Delta extends Iterable { return Delta(ops); } - Delta chop() { + void chop() { if (_operations.isEmpty) { - return this; + return; } _rawString = null; final lastOp = _operations.last; if (lastOp is TextRetain && (lastOp.attributes?.length ?? 0) == 0) { _operations.removeLast(); } - return this; } @override @@ -477,7 +467,7 @@ class Delta extends Iterable { } return previousValue; }); - return inverted.chop(); + return inverted..chop(); } List toJson() { diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart index 918f68118d..305791b519 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart @@ -113,22 +113,32 @@ class TransactionBuilder { } textEdit( node, - () => Delta().retain(index).insert( - content, - newAttributes, - ), + () => Delta() + ..retain(index) + ..insert( + content, + newAttributes, + ), ); afterSelection = Selection.collapsed( Position(path: node.path, offset: index + content.length)); } formatText(TextNode node, int index, int length, Attributes attributes) { - textEdit(node, () => Delta().retain(index).retain(length, attributes)); + textEdit( + node, + () => Delta() + ..retain(index) + ..retain(length, attributes)); afterSelection = beforeSelection; } deleteText(TextNode node, int index, int length) { - textEdit(node, () => Delta().retain(index).delete(length)); + textEdit( + node, + () => Delta() + ..retain(index) + ..delete(length)); afterSelection = Selection.collapsed(Position(path: node.path, offset: index)); } @@ -144,7 +154,10 @@ class TransactionBuilder { } textEdit( node, - () => Delta().retain(index).delete(length).insert(content, newAttributes), + () => Delta() + ..retain(index) + ..delete(length) + ..insert(content, newAttributes), ); afterSelection = Selection.collapsed( Position( diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart index debce245c2..0b87fc0fd4 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart @@ -67,7 +67,7 @@ _pasteHTML(EditorState editorState, String html) { final textNodeAtPath = nodeAtPath as TextNode; final firstTextNode = firstNode as TextNode; tb.textEdit(textNodeAtPath, - () => Delta().retain(startOffset).concat(firstTextNode.delta)); + () => (Delta()..retain(startOffset)) + firstTextNode.delta); tb.setAfterSelection(Selection.collapsed(Position( path: path, offset: startOffset + firstTextNode.delta.length))); tb.commit(); @@ -93,17 +93,18 @@ _pasteMultipleLinesInText( tb.textEdit( textNodeAtPath, - () => Delta() - .retain(offset) - .delete(remain.length) - .concat(firstTextNode.delta)); + () => + (Delta() + ..retain(offset) + ..delete(remain.length)) + + firstTextNode.delta); final tailNodes = nodes.sublist(1); path[path.length - 1]++; if (tailNodes.isNotEmpty) { if (tailNodes.last.type == "text") { final tailTextNode = tailNodes.last as TextNode; - tailTextNode.delta = tailTextNode.delta.concat(remain); + tailTextNode.delta = tailTextNode.delta + remain; } else if (remain.length > 0) { tailNodes.add(TextNode(type: "text", delta: remain)); } @@ -151,7 +152,11 @@ _handlePastePlainText(EditorState editorState, String plainText) { editorState.document.nodeAtPath(selection.end.path)! as TextNode; final beginOffset = selection.end.offset; TransactionBuilder(editorState) - ..textEdit(node, () => Delta().retain(beginOffset).insert(lines[0])) + ..textEdit( + node, + () => Delta() + ..retain(beginOffset) + ..insert(lines[0])) ..setAfterSelection(Selection.collapsed(Position( path: selection.end.path, offset: beginOffset + lines[0].length))) ..commit(); @@ -175,17 +180,20 @@ _handlePastePlainText(EditorState editorState, String plainText) { final nodes = remains.map((e) { if (index++ == remains.length - 1) { return TextNode( - type: "text", delta: Delta().insert(e).addAll(insertedLineSuffix)); + type: "text", + delta: Delta() + ..insert(e) + ..addAll(insertedLineSuffix)); } - return TextNode(type: "text", delta: Delta().insert(e)); + return TextNode(type: "text", delta: Delta()..insert(e)); }).toList(); // insert first line tb.textEdit( node, () => Delta() - .retain(beginOffset) - .insert(firstLine) - .delete(node.delta.length - beginOffset)); + ..retain(beginOffset) + ..insert(firstLine) + ..delete(node.delta.length - beginOffset)); // insert remains tb.insertNodes(path, nodes); tb.commit(); @@ -226,7 +234,10 @@ _deleteSelectedContent(EditorState editorState) { final tb = TransactionBuilder(editorState); final len = selection.end.offset - selection.start.offset; tb.textEdit( - textItem, () => Delta().retain(selection.start.offset).delete(len)); + textItem, + () => Delta() + ..retain(selection.start.offset) + ..delete(len)); tb.setAfterSelection(Selection.collapsed(selection.start)); tb.commit(); return; @@ -240,8 +251,9 @@ _deleteSelectedContent(EditorState editorState) { final textItem = item as TextNode; final deleteLen = textItem.delta.length - selection.start.offset; tb.textEdit(textItem, () { - final delta = Delta(); - delta.retain(selection.start.offset).delete(deleteLen); + final delta = Delta() + ..retain(selection.start.offset) + ..delete(deleteLen); if (endNode is TextNode) { final remain = endNode.delta.slice(selection.end.offset); diff --git a/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart b/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart index c62f600266..7016da70e4 100644 --- a/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart +++ b/frontend/app_flowy/packages/flowy_editor/test/delta_test.dart @@ -14,9 +14,12 @@ void main() { }) ]); - final death = Delta().retain(12).insert("White", { - 'color': '#fff', - }).delete(4); + final death = Delta() + ..retain(12) + ..insert("White", { + 'color': '#fff', + }) + ..delete(4); final restores = delta.compose(death); expect(restores.toList(), [ @@ -26,164 +29,203 @@ void main() { ]); }); test('compose()', () { - final a = Delta().insert('A'); - final b = Delta().insert('B'); - final expected = Delta().insert('B').insert('A'); + final a = Delta()..insert('A'); + final b = Delta()..insert('B'); + final expected = Delta() + ..insert('B') + ..insert('A'); expect(a.compose(b), expected); }); test('insert + retain', () { - final a = Delta().insert('A'); - final b = Delta().retain(1, { - 'bold': true, - 'color': 'red', - }); - final expected = Delta().insert('A', { - 'bold': true, - 'color': 'red', - }); + final a = Delta()..insert('A'); + final b = Delta() + ..retain(1, { + 'bold': true, + 'color': 'red', + }); + final expected = Delta() + ..insert('A', { + 'bold': true, + 'color': 'red', + }); expect(a.compose(b), expected); }); test('insert + delete', () { - final a = Delta().insert('A'); - final b = Delta().delete(1); + final a = Delta()..insert('A'); + final b = Delta()..delete(1); final expected = Delta(); expect(a.compose(b), expected); }); test('delete + insert', () { - final a = Delta().delete(1); - final b = Delta().insert('B'); - final expected = Delta().insert('B').delete(1); + final a = Delta()..delete(1); + final b = Delta()..insert('B'); + final expected = Delta() + ..insert('B') + ..delete(1); expect(a.compose(b), expected); }); test('delete + retain', () { - final a = Delta().delete(1); - final b = Delta().retain(1, { - 'bold': true, - 'color': 'red', - }); - final expected = Delta().delete(1).retain(1, { - 'bold': true, - 'color': 'red', - }); + final a = Delta()..delete(1); + final b = Delta() + ..retain(1, { + 'bold': true, + 'color': 'red', + }); + final expected = Delta() + ..delete(1) + ..retain(1, { + 'bold': true, + 'color': 'red', + }); expect(a.compose(b), expected); }); test('delete + delete', () { - final a = Delta().delete(1); - final b = Delta().delete(1); - final expected = Delta().delete(2); + final a = Delta()..delete(1); + final b = Delta()..delete(1); + final expected = Delta()..delete(2); expect(a.compose(b), expected); }); test('retain + insert', () { - final a = Delta().retain(1, {'color': 'blue'}); - final b = Delta().insert('B'); - final expected = Delta().insert('B').retain(1, { - 'color': 'blue', - }); + final a = Delta()..retain(1, {'color': 'blue'}); + final b = Delta()..insert('B'); + final expected = Delta() + ..insert('B') + ..retain(1, { + 'color': 'blue', + }); expect(a.compose(b), expected); }); test('retain + retain', () { - final a = Delta().retain(1, { - 'color': 'blue', - }); - final b = Delta().retain(1, { - 'bold': true, - 'color': 'red', - }); - final expected = Delta().retain(1, { - 'bold': true, - 'color': 'red', - }); + final a = Delta() + ..retain(1, { + 'color': 'blue', + }); + final b = Delta() + ..retain(1, { + 'bold': true, + 'color': 'red', + }); + final expected = Delta() + ..retain(1, { + 'bold': true, + 'color': 'red', + }); expect(a.compose(b), expected); }); test('retain + delete', () { - final a = Delta().retain(1, { - 'color': 'blue', - }); - final b = Delta().delete(1); - final expected = Delta().delete(1); + final a = Delta() + ..retain(1, { + 'color': 'blue', + }); + final b = Delta()..delete(1); + final expected = Delta()..delete(1); expect(a.compose(b), expected); }); test('insert in middle of text', () { - final a = Delta().insert('Hello'); - final b = Delta().retain(3).insert('X'); - final expected = Delta().insert('HelXlo'); + final a = Delta()..insert('Hello'); + final b = Delta() + ..retain(3) + ..insert('X'); + final expected = Delta()..insert('HelXlo'); expect(a.compose(b), expected); }); test('insert and delete ordering', () { - final a = Delta().insert('Hello'); - final b = Delta().insert('Hello'); - final insertFirst = Delta().retain(3).insert('X').delete(1); - final deleteFirst = Delta().retain(3).delete(1).insert('X'); - final expected = Delta().insert('HelXo'); + final a = Delta()..insert('Hello'); + final b = Delta()..insert('Hello'); + final insertFirst = Delta() + ..retain(3) + ..insert('X') + ..delete(1); + final deleteFirst = Delta() + ..retain(3) + ..delete(1) + ..insert('X'); + final expected = Delta()..insert('HelXo'); expect(a.compose(insertFirst), expected); expect(b.compose(deleteFirst), expected); }); test('delete entire text', () { - final a = Delta().retain(4).insert('Hello'); - final b = Delta().delete(9); - final expected = Delta().delete(4); + final a = Delta() + ..retain(4) + ..insert('Hello'); + final b = Delta()..delete(9); + final expected = Delta()..delete(4); expect(a.compose(b), expected); }); test('retain more than length of text', () { - final a = Delta().insert('Hello'); - final b = Delta().retain(10); - final expected = Delta().insert('Hello'); + final a = Delta()..insert('Hello'); + final b = Delta()..retain(10); + final expected = Delta()..insert('Hello'); expect(a.compose(b), expected); }); test('retain start optimization', () { final a = Delta() - .insert('A', {'bold': true}) - .insert('B') - .insert('C', {'bold': true}) - .delete(1); - final b = Delta().retain(3).insert('D'); + ..insert('A', {'bold': true}) + ..insert('B') + ..insert('C', {'bold': true}) + ..delete(1); + final b = Delta() + ..retain(3) + ..insert('D'); final expected = Delta() - .insert('A', {'bold': true}) - .insert('B') - .insert('C', {'bold': true}) - .insert('D') - .delete(1); + ..insert('A', {'bold': true}) + ..insert('B') + ..insert('C', {'bold': true}) + ..insert('D') + ..delete(1); expect(a.compose(b), expected); }); test('retain end optimization', () { final a = Delta() - .insert('A', {'bold': true}) - .insert('B') - .insert('C', {'bold': true}); - final b = Delta().delete(1); - final expected = Delta().insert('B').insert('C', {'bold': true}); + ..insert('A', {'bold': true}) + ..insert('B') + ..insert('C', {'bold': true}); + final b = Delta()..delete(1); + final expected = Delta() + ..insert('B') + ..insert('C', {'bold': true}); expect(a.compose(b), expected); }); test('retain end optimization join', () { final a = Delta() - .insert('A', {'bold': true}) - .insert('B') - .insert('C', {'bold': true}) - .insert('D') - .insert('E', {'bold': true}) - .insert('F'); - final b = Delta().retain(1).delete(1); + ..insert('A', {'bold': true}) + ..insert('B') + ..insert('C', {'bold': true}) + ..insert('D') + ..insert('E', {'bold': true}) + ..insert('F'); + final b = Delta() + ..retain(1) + ..delete(1); final expected = Delta() - .insert('AC', {'bold': true}) - .insert('D') - .insert('E', {'bold': true}) - .insert('F'); + ..insert('AC', {'bold': true}) + ..insert('D') + ..insert('E', {'bold': true}) + ..insert('F'); expect(a.compose(b), expected); }); }); group('invert', () { test('insert', () { - final delta = Delta().retain(2).insert('A'); - final base = Delta().insert('12346'); - final expected = Delta().retain(2).delete(1); + final delta = Delta() + ..retain(2) + ..insert('A'); + final base = Delta()..insert('12346'); + final expected = Delta() + ..retain(2) + ..delete(1); final inverted = delta.invert(base); expect(expected, inverted); expect(base.compose(delta).compose(inverted), base); }); test('delete', () { - final delta = Delta().retain(2).delete(3); - final base = Delta().insert('123456'); - final expected = Delta().retain(2).insert('345'); + final delta = Delta() + ..retain(2) + ..delete(3); + final base = Delta()..insert('123456'); + final expected = Delta() + ..retain(2) + ..insert('345'); final inverted = delta.invert(base); expect(expected, inverted); expect(base.compose(delta).compose(inverted), base); @@ -199,7 +241,10 @@ void main() { }); group('json', () { test('toJson()', () { - final delta = Delta().retain(2).insert('A').delete(3); + final delta = Delta() + ..retain(2) + ..insert('A') + ..delete(3); expect(delta.toJson(), [ {'retain': 2}, {'insert': 'A'}, @@ -207,8 +252,9 @@ void main() { ]); }); test('attributes', () { - final delta = - Delta().retain(2, {'bold': true}).insert('A', {'italic': true}); + final delta = Delta() + ..retain(2, {'bold': true}) + ..insert('A', {'italic': true}); expect(delta.toJson(), [ { 'retain': 2, @@ -226,7 +272,10 @@ void main() { {'insert': 'A'}, {'delete': 3}, ]); - final expected = Delta().retain(2).insert('A').delete(3); + final expected = Delta() + ..retain(2) + ..insert('A') + ..delete(3); expect(delta, expected); }); });