From f708afe67325199d783bfc6291b2b2ba5ee24563 Mon Sep 17 00:00:00 2001
From: "Lucas.Xu" <lucas.xu@appflowy.io>
Date: Thu, 11 Aug 2022 20:14:36 +0800
Subject: [PATCH] fix: #827

---
 .../lib/src/document/selection.dart           |  2 +
 .../src/extensions/text_node_extensions.dart  |  9 ++--
 .../format_rich_text_style.dart               | 47 +++++++++----------
 .../lib/src/service/selection_service.dart    |  1 +
 4 files changed, 32 insertions(+), 27 deletions(-)

diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart
index 68aecba8fc..641a985577 100644
--- a/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart
+++ b/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart
@@ -46,6 +46,8 @@ class Selection {
       (start.path <= end.path && !pathEquals(start.path, end.path)) ||
       (isSingle && start.offset < end.offset);
 
+  Selection get reversed => copyWith(start: end, end: start);
+
   Selection collapse({bool atStart = false}) {
     if (atStart) {
       return Selection(start: start, end: start);
diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart
index 131255ab63..3408546c42 100644
--- a/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart
+++ b/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart
@@ -20,14 +20,17 @@ extension TextNodeExtension on TextNode {
 
   bool allSatisfyInSelection(String styleKey, Selection selection) {
     final ops = delta.whereType<TextInsert>();
+    final startOffset =
+        selection.isBackward ? selection.start.offset : selection.end.offset;
+    final endOffset =
+        selection.isBackward ? selection.end.offset : selection.start.offset;
     var start = 0;
     for (final op in ops) {
-      if (start >= selection.end.offset) {
+      if (start >= endOffset) {
         break;
       }
       final length = op.length;
-      if (start < selection.end.offset &&
-          start + length > selection.start.offset) {
+      if (start < endOffset && start + length > startOffset) {
         if (op.attributes == null ||
             !op.attributes!.containsKey(styleKey) ||
             op.attributes![styleKey] == false) {
diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart
index 6830dd62e4..64cd4f332e 100644
--- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart
+++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart
@@ -43,7 +43,7 @@ bool insertTextNodeAfterSelection(
   }
 
   final node = nodes.first;
-  if (node is TextNode && node.delta.length == 0) {
+  if (node is TextNode && node.delta.isEmpty) {
     formatTextNodes(editorState, attributes);
   } else {
     final next = selection.end.path.next;
@@ -157,11 +157,18 @@ bool formatRichTextPartialStyle(EditorState editorState, String styleKey) {
 }
 
 bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
-  final selection = editorState.service.selectionService.currentSelection.value;
-  final nodes = editorState.service.selectionService.currentSelectedNodes;
-  final textNodes = nodes.whereType<TextNode>().toList();
+  var selection = editorState.service.selectionService.currentSelection.value;
+  var nodes = editorState.service.selectionService.currentSelectedNodes;
 
-  if (selection == null || textNodes.isEmpty) {
+  if (selection == null) {
+    return false;
+  }
+
+  nodes = selection.isBackward ? nodes : nodes.reversed.toList(growable: false);
+  selection = selection.isBackward ? selection : selection.reversed;
+
+  var textNodes = nodes.whereType<TextNode>().toList();
+  if (textNodes.isEmpty) {
     return false;
   }
 
@@ -180,28 +187,20 @@ bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
   } else {
     for (var i = 0; i < textNodes.length; i++) {
       final textNode = textNodes[i];
+      var index = 0;
+      var length = textNode.toRawString().length;
       if (i == 0 && textNode == nodes.first) {
-        builder.formatText(
-          textNode,
-          selection.start.offset,
-          textNode.toRawString().length - selection.start.offset,
-          attributes,
-        );
+        index = selection.start.offset;
+        length = textNode.toRawString().length - selection.start.offset;
       } else if (i == textNodes.length - 1 && textNode == nodes.last) {
-        builder.formatText(
-          textNode,
-          0,
-          selection.end.offset,
-          attributes,
-        );
-      } else {
-        builder.formatText(
-          textNode,
-          0,
-          textNode.toRawString().length,
-          attributes,
-        );
+        length = selection.end.offset;
       }
+      builder.formatText(
+        textNode,
+        index,
+        length,
+        attributes,
+      );
     }
   }
 
diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart
index 552e9eaf69..ecf013d0a4 100644
--- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart
+++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart
@@ -487,6 +487,7 @@ class _FlowySelectionState extends State<FlowySelection>
         max = mid - 1;
       }
     }
+    min = min.clamp(start, end);
     final node = sortedNodes[min];
     if (node.children.isNotEmpty && node.children.first.rect.top <= offset.dy) {
       final children = node.children.toList(growable: false);