mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-23 05:24:51 +00:00
fix: how to find best insert pos for richtext & expand type reverse behavior (#250)
* chore: bump loro-crdt version * fix: find best insert pos * fix: style anchors' ExpandType's reverse behavior
This commit is contained in:
parent
3a2c9523cd
commit
b5aa622554
3 changed files with 36 additions and 28 deletions
|
@ -63,6 +63,13 @@ impl LoroValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_false(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
LoroValue::Bool(b) => !*b,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_depth(&self) -> usize {
|
pub fn get_depth(&self) -> usize {
|
||||||
let mut max_depth = 0;
|
let mut max_depth = 0;
|
||||||
let mut value_depth_pairs = vec![(self, 0)];
|
let mut value_depth_pairs = vec![(self, 0)];
|
||||||
|
|
|
@ -121,6 +121,8 @@ impl Ord for StyleOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: We can remove this type already
|
||||||
|
///
|
||||||
/// A compact representation of a rich text style config.
|
/// A compact representation of a rich text style config.
|
||||||
///
|
///
|
||||||
/// Note: we assume style with the same key has the same `Mergeable` and `isContainer` value.
|
/// Note: we assume style with the same key has the same `Mergeable` and `isContainer` value.
|
||||||
|
@ -128,11 +130,11 @@ impl Ord for StyleOp {
|
||||||
/// - 0 (1st bit)
|
/// - 0 (1st bit)
|
||||||
/// - Expand Before (2nd bit): when inserting new text before this style, whether the new text should inherit this style.
|
/// - Expand Before (2nd bit): when inserting new text before this style, whether the new text should inherit this style.
|
||||||
/// - Expand After (3rd bit): when inserting new text after this style, whether the new text should inherit this style.
|
/// - Expand After (3rd bit): when inserting new text after this style, whether the new text should inherit this style.
|
||||||
/// - Delete (4th bit): whether this is used to remove a style from a range.
|
/// - 0 (4th bit):
|
||||||
/// - 0 (5th bit): whether the style also store other data in a associated map container with the same OpID.
|
/// - 0 (5th bit):
|
||||||
/// - 0 (6th bit)
|
/// - 0 (6th bit)
|
||||||
/// - 0 (7th bit)
|
/// - 0 (7th bit)
|
||||||
/// - isAlive (8th bit): always 1 unless the style is garbage collected. If this is 0, all other bits should be 0 as well.
|
/// - 0 (8th bit):
|
||||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
#[derive(Default, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct TextStyleInfoFlag {
|
pub struct TextStyleInfoFlag {
|
||||||
data: u8,
|
data: u8,
|
||||||
|
@ -151,7 +153,6 @@ impl Debug for TextStyleInfoFlag {
|
||||||
|
|
||||||
const EXPAND_BEFORE_MASK: u8 = 0b0000_0010;
|
const EXPAND_BEFORE_MASK: u8 = 0b0000_0010;
|
||||||
const EXPAND_AFTER_MASK: u8 = 0b0000_0100;
|
const EXPAND_AFTER_MASK: u8 = 0b0000_0100;
|
||||||
const DELETE_MASK: u8 = 0b0000_1000;
|
|
||||||
const ALIVE_MASK: u8 = 0b1000_0000;
|
const ALIVE_MASK: u8 = 0b1000_0000;
|
||||||
|
|
||||||
/// Whether to expand the style when inserting new text around it.
|
/// Whether to expand the style when inserting new text around it.
|
||||||
|
@ -198,19 +199,22 @@ impl ExpandType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create reversed expand type.
|
/// Toggle expand type between for deletion and for creation
|
||||||
///
|
///
|
||||||
/// Before -> After
|
/// For a style that expand after, when we delete the style, we need to have another style that expands after to nullify it,
|
||||||
/// After -> Before
|
/// so that the expand behavior is not changed.
|
||||||
|
///
|
||||||
|
/// Before -> Before
|
||||||
|
/// After -> After
|
||||||
/// Both -> None
|
/// Both -> None
|
||||||
/// None -> Both
|
/// None -> Both
|
||||||
///
|
///
|
||||||
/// Because the creation of text styles and the deletion of the text styles have reversed expand type.
|
/// Because the creation of text styles and the deletion of the text styles have reversed expand type.
|
||||||
/// This method is useful to convert between the two
|
/// This method is useful to convert between the two
|
||||||
pub fn reverse(self) -> Self {
|
pub const fn reverse(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
ExpandType::Before => ExpandType::After,
|
ExpandType::Before => ExpandType::Before,
|
||||||
ExpandType::After => ExpandType::Before,
|
ExpandType::After => ExpandType::After,
|
||||||
ExpandType::Both => ExpandType::None,
|
ExpandType::Both => ExpandType::None,
|
||||||
ExpandType::None => ExpandType::Both,
|
ExpandType::None => ExpandType::Both,
|
||||||
}
|
}
|
||||||
|
@ -220,16 +224,25 @@ impl ExpandType {
|
||||||
impl TextStyleInfoFlag {
|
impl TextStyleInfoFlag {
|
||||||
/// When inserting new text around this style, prefer inserting after it.
|
/// When inserting new text around this style, prefer inserting after it.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn expand_before(self) -> bool {
|
pub const fn expand_before(self) -> bool {
|
||||||
self.data & EXPAND_BEFORE_MASK != 0
|
self.data & EXPAND_BEFORE_MASK != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When inserting new text around this style, prefer inserting before it.
|
/// When inserting new text around this style, prefer inserting before it.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn expand_after(self) -> bool {
|
pub const fn expand_after(self) -> bool {
|
||||||
self.data & EXPAND_AFTER_MASK != 0
|
self.data & EXPAND_AFTER_MASK != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn expand_type(self) -> ExpandType {
|
||||||
|
match (self.expand_before(), self.expand_after()) {
|
||||||
|
(true, true) => ExpandType::Both,
|
||||||
|
(true, false) => ExpandType::Before,
|
||||||
|
(false, true) => ExpandType::After,
|
||||||
|
(false, false) => ExpandType::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This method tells that when we can insert text before/after this style anchor, whether we insert the new text before the anchor.
|
/// This method tells that when we can insert text before/after this style anchor, whether we insert the new text before the anchor.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn prefer_insert_before(self, anchor_type: AnchorType) -> bool {
|
pub fn prefer_insert_before(self, anchor_type: AnchorType) -> bool {
|
||||||
|
@ -257,23 +270,9 @@ impl TextStyleInfoFlag {
|
||||||
TextStyleInfoFlag { data }
|
TextStyleInfoFlag { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_dead(self) -> bool {
|
|
||||||
debug_assert!((self.data & ALIVE_MASK != 0) || self.data == 0);
|
|
||||||
(self.data & ALIVE_MASK) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn to_delete(self) -> Self {
|
pub const fn to_delete(self) -> Self {
|
||||||
let mut data = self.data;
|
TextStyleInfoFlag::new(self.expand_type().reverse())
|
||||||
if data & DELETE_MASK > 0 {
|
|
||||||
return Self { data };
|
|
||||||
}
|
|
||||||
|
|
||||||
// set is_delete
|
|
||||||
data |= DELETE_MASK;
|
|
||||||
// invert expand type
|
|
||||||
data ^= EXPAND_AFTER_MASK | EXPAND_BEFORE_MASK;
|
|
||||||
Self { data }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const BOLD: TextStyleInfoFlag = TextStyleInfoFlag::new(ExpandType::After);
|
pub const BOLD: TextStyleInfoFlag = TextStyleInfoFlag::new(ExpandType::After);
|
||||||
|
|
|
@ -1527,7 +1527,9 @@ impl RichtextState {
|
||||||
};
|
};
|
||||||
|
|
||||||
visited.push((style, anchor_type, iter, entity_index));
|
visited.push((style, anchor_type, iter, entity_index));
|
||||||
if anchor_type == AnchorType::Start {
|
if anchor_type == AnchorType::Start
|
||||||
|
&& (!style.value.is_null() || !style.value.is_false())
|
||||||
|
{
|
||||||
// case 1. should be before this anchor
|
// case 1. should be before this anchor
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue