refactor: move selection to core/location

This commit is contained in:
Lucas.Xu 2022-10-10 10:39:42 +08:00
parent b0257a626d
commit d02c29426e
27 changed files with 158 additions and 73 deletions

View File

@ -5,8 +5,8 @@ export 'src/infra/log.dart';
export 'src/render/style/editor_style.dart';
export 'src/core/document/node.dart';
export 'src/core/document/path.dart';
export 'src/core/selection/position.dart';
export 'src/document/selection.dart';
export 'src/core/location/position.dart';
export 'src/core/location/selection.dart';
export 'src/document/state_tree.dart';
export 'src/core/document/text_delta.dart';
export 'src/core/document/attributes.dart';

View File

@ -4,7 +4,7 @@ import 'package:appflowy_editor/src/core/document/attributes.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
Future<void> formatBuiltInTextAttributes(

View File

@ -4,7 +4,7 @@ import 'package:appflowy_editor/src/commands/text_command_infra.dart';
import 'package:appflowy_editor/src/core/document/attributes.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
import 'package:flutter/widgets.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
// get formatted [TextNode]

View File

@ -1,5 +1,5 @@
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
/// Selection represents the selected area or the cursor area in the editor.
///
@ -36,31 +36,58 @@ class Selection {
final Position start;
final Position end;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Selection && other.start == start && other.end == end;
}
@override
int get hashCode => start.hashCode ^ end.hashCode;
@override
String toString() => 'start = $start, end = $end';
/// Returns a Boolean indicating whether the selection's start and end points
/// are at the same position.
bool get isCollapsed => start == end;
/// Returns a Boolean indicating whether the selection's start and end points
/// are at the same path.
bool get isSingle => start.path.equals(end.path);
/// Returns a Boolean indicating whether the selection is forward.
bool get isForward =>
(start.path > end.path) || (isSingle && start.offset > end.offset);
/// Returns a Boolean indicating whether the selection is backward.
bool get isBackward =>
(start.path < end.path) || (isSingle && start.offset < end.offset);
Selection get normalize {
if (isForward) {
return reversed;
}
return this;
}
/// Returns a normalized selection that direction is forward.
Selection get normalized => isBackward ? copyWith() : reversed.copyWith();
/// Returns a reversed selection.
Selection get reversed => copyWith(start: end, end: start);
int get startIndex => normalize.start.offset;
int get endIndex => normalize.end.offset;
/// Returns the offset in the starting position under the normalized selection.
int get startIndex => normalized.start.offset;
/// Returns the offset in the ending position under the normalized selection.
int get endIndex => normalized.end.offset;
int get length => endIndex - startIndex;
/// Collapses the current selection to a single point.
///
/// If [atStart] is true, the selection will be collapsed to the start point.
/// If [atStart] is false, the selection will be collapsed to the end point.
Selection collapse({bool atStart = false}) {
if (atStart) {
return Selection(start: start, end: start);
return copyWith(end: start);
} else {
return Selection(start: end, end: end);
return copyWith(start: end);
}
}
@ -71,29 +98,10 @@ class Selection {
);
}
Selection copy() => Selection(start: start, end: end);
Map<String, dynamic> toJson() {
return {
'start': start.toJson(),
'end': end.toJson(),
};
}
@override
bool operator ==(Object other) {
if (other is! Selection) {
return false;
}
if (identical(this, other)) {
return true;
}
return start == other.start && end == other.end;
}
@override
int get hashCode => Object.hash(start, end);
@override
String toString() => '[Selection] start = $start, end = $end';
}

View File

@ -5,7 +5,7 @@ import 'package:appflowy_editor/src/render/style/editor_style.dart';
import 'package:appflowy_editor/src/service/service.dart';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/document/state_tree.dart';
import 'package:appflowy_editor/src/operation/operation.dart';
import 'package:appflowy_editor/src/operation/transaction.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
import 'package:appflowy_editor/src/render/selection/selectable.dart';
import 'package:flutter/material.dart';

View File

@ -1,7 +1,7 @@
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/core/document/text_delta.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';

View File

@ -1,6 +1,6 @@
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import './operation.dart';
/// A [Transaction] has a list of [Operation] objects that will be applied

View File

@ -4,8 +4,8 @@ import 'dart:math';
import 'package:appflowy_editor/src/core/document/attributes.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/core/document/text_delta.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/operation/operation.dart';

View File

@ -1,7 +1,7 @@
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/render/selection/selectable.dart';
import 'package:flutter/material.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/render/selection/selectable.dart';
import 'package:flutter/material.dart';

View File

@ -7,8 +7,8 @@ import 'package:flutter/rendering.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/core/document/text_delta.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:flutter/material.dart';
enum CursorStyle {

View File

@ -1,8 +1,8 @@
import 'package:appflowy_editor/src/core/document/attributes.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/node_extensions.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -220,7 +220,7 @@ ShortcutEventHandler cursorEndSelect = (editorState, event) {
KeyEventResult cursorUp(EditorState editorState, RawKeyEvent event) {
final nodes = editorState.service.selectionService.currentSelectedNodes;
final selection =
editorState.service.selectionService.currentSelection.value?.normalize;
editorState.service.selectionService.currentSelection.value?.normalized;
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
@ -234,7 +234,7 @@ KeyEventResult cursorUp(EditorState editorState, RawKeyEvent event) {
KeyEventResult cursorDown(EditorState editorState, RawKeyEvent event) {
final nodes = editorState.service.selectionService.currentSelectedNodes;
final selection =
editorState.service.selectionService.currentSelection.value?.normalize;
editorState.service.selectionService.currentSelection.value?.normalized;
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
@ -248,7 +248,7 @@ KeyEventResult cursorDown(EditorState editorState, RawKeyEvent event) {
KeyEventResult cursorLeft(EditorState editorState, RawKeyEvent event) {
final nodes = editorState.service.selectionService.currentSelectedNodes;
final selection =
editorState.service.selectionService.currentSelection.value?.normalize;
editorState.service.selectionService.currentSelection.value?.normalized;
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}
@ -270,7 +270,7 @@ KeyEventResult cursorLeft(EditorState editorState, RawKeyEvent event) {
KeyEventResult cursorRight(EditorState editorState, RawKeyEvent event) {
final nodes = editorState.service.selectionService.currentSelectedNodes;
final selection =
editorState.service.selectionService.currentSelection.value?.normalize;
editorState.service.selectionService.currentSelection.value?.normalized;
if (nodes.isEmpty || selection == null) {
return KeyEventResult.ignored;
}

View File

@ -25,7 +25,7 @@ Selection _computeSelectionAfterPasteMultipleNodes(
}
void _handleCopy(EditorState editorState) async {
final selection = editorState.cursorSelection?.normalize;
final selection = editorState.cursorSelection?.normalized;
if (selection == null || selection.isCollapsed) {
return;
}
@ -65,7 +65,7 @@ void _handleCopy(EditorState editorState) async {
}
void _pasteHTML(EditorState editorState, String html) {
final selection = editorState.cursorSelection?.normalize;
final selection = editorState.cursorSelection?.normalized;
if (selection == null) {
return;
}
@ -234,7 +234,7 @@ Delta _lineContentToDelta(String lineContent) {
}
void _handlePastePlainText(EditorState editorState, String plainText) {
final selection = editorState.cursorSelection?.normalize;
final selection = editorState.cursorSelection?.normalized;
if (selection == null) {
return;
}
@ -300,7 +300,7 @@ void _handleCut(EditorState editorState) {
}
void _deleteSelectedContent(EditorState editorState) {
final selection = editorState.cursorSelection?.normalize;
final selection = editorState.cursorSelection?.normalized;
if (selection == null || selection.isCollapsed) {
return;
}

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart';
import 'package:flutter/material.dart';

View File

@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
import './number_list_helper.dart';

View File

@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/document/node_iterator.dart';
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/node_extensions.dart';
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
@ -366,7 +366,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
final backwardNodes =
selection.isBackward ? nodes : nodes.reversed.toList(growable: false);
final normalizedSelection = selection.normalize;
final normalizedSelection = selection.normalized;
assert(normalizedSelection.isBackward);
Log.selection.debug('update selection areas, $normalizedSelection');
@ -378,7 +378,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
continue;
}
var newSelection = normalizedSelection.copy();
var newSelection = normalizedSelection.copyWith();
/// In the case of multiple selections,
/// we need to return a new selection for each selected node individually.

View File

@ -1,6 +1,6 @@
import 'dart:collection';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/infra/log.dart';
import 'package:appflowy_editor/src/operation/operation.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -0,0 +1,77 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
void main() async {
group('selection.dart', () {
test('test selection equality', () {
final position = Position(path: [0, 1, 2], offset: 3);
final selectionA = Selection(start: position, end: position);
final selectionB = Selection.collapsed(position);
expect(selectionA, selectionB);
expect(selectionA.hashCode, selectionB.hashCode);
final newPosition = Position(path: [1, 2, 3], offset: 4);
final selectionC = selectionA.copyWith(start: newPosition);
expect(selectionC.start, newPosition);
expect(selectionC.end, position);
expect(selectionC.isCollapsed, false);
final selectionD = selectionA.copyWith(end: newPosition);
expect(selectionD.start, position);
expect(selectionD.end, newPosition);
expect(selectionD.isCollapsed, false);
final selectionE = Selection.single(path: [0, 1, 2], startOffset: 3);
expect(selectionE, selectionA);
expect(selectionE.isSingle, true);
expect(selectionE.isCollapsed, true);
});
test('test selection direction', () {
final start = Position(path: [0, 1, 2], offset: 3);
final end = Position(path: [1, 2, 3], offset: 3);
final backwardSelection = Selection(start: start, end: end);
expect(backwardSelection.isBackward, true);
final forwardSelection = Selection(start: end, end: start);
expect(forwardSelection.isForward, true);
expect(backwardSelection.reversed, forwardSelection);
expect(forwardSelection.normalized, backwardSelection);
expect(backwardSelection.startIndex, 3);
expect(backwardSelection.endIndex, 3);
});
test('test selection collapsed', () {
final start = Position(path: [0, 1, 2], offset: 3);
final end = Position(path: [1, 2, 3], offset: 3);
final selection = Selection(start: start, end: end);
final collapsedAtStart = selection.collapse(atStart: true);
expect(collapsedAtStart.isCollapsed, true);
expect(collapsedAtStart.start, start);
expect(collapsedAtStart.end, start);
final collapsedAtEnd = selection.collapse(atStart: false);
expect(collapsedAtEnd.isCollapsed, true);
expect(collapsedAtEnd.start, end);
expect(collapsedAtEnd.end, end);
});
test('test selection toJson', () {
final start = Position(path: [0, 1, 2], offset: 3);
final end = Position(path: [1, 2, 3], offset: 3);
final selection = Selection(start: start, end: end);
expect(selection.toJson(), {
'start': {
'path': [0, 1, 2],
'offset': 3
},
'end': {
'path': [1, 2, 3],
'offset': 3
}
});
});
});
}

View File

@ -1,6 +1,6 @@
import 'package:appflowy_editor/src/core/document/path.dart';
import 'package:appflowy_editor/src/core/selection/position.dart';
import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {