mirror of
https://github.com/loro-dev/loro.git
synced 2025-02-06 12:25:03 +00:00
refactor: rename stable pos to cursor (#317)
This commit is contained in:
parent
454b4088a6
commit
1918cd7ac3
11 changed files with 59 additions and 54 deletions
|
@ -5,7 +5,7 @@ use generic_btree::{
|
||||||
use loro_common::{Counter, HasId, HasIdSpan, IdFull, IdSpan, Lamport, PeerID, ID};
|
use loro_common::{Counter, HasId, HasIdSpan, IdFull, IdSpan, Lamport, PeerID, ID};
|
||||||
use rle::HasLength;
|
use rle::HasLength;
|
||||||
|
|
||||||
use crate::{stable_pos::AbsolutePosition, VersionVector};
|
use crate::{cursor::AbsolutePosition, VersionVector};
|
||||||
|
|
||||||
use self::{crdt_rope::CrdtRope, id_to_cursor::IdToCursor};
|
use self::{crdt_rope::CrdtRope, id_to_cursor::IdToCursor};
|
||||||
|
|
||||||
|
@ -386,9 +386,9 @@ impl Tracker {
|
||||||
return Some(AbsolutePosition {
|
return Some(AbsolutePosition {
|
||||||
pos: index,
|
pos: index,
|
||||||
side: if is_activated {
|
side: if is_activated {
|
||||||
crate::stable_pos::Side::Middle
|
crate::cursor::Side::Middle
|
||||||
} else {
|
} else {
|
||||||
crate::stable_pos::Side::Left
|
crate::cursor::Side::Left
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ use crate::{
|
||||||
AnchorType, CrdtRopeDelta, RichtextChunk, RichtextChunkValue, RichtextTracker, StyleOp,
|
AnchorType, CrdtRopeDelta, RichtextChunk, RichtextChunkValue, RichtextTracker, StyleOp,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
cursor::AbsolutePosition,
|
||||||
delta::{Delta, MapDelta, MapValue},
|
delta::{Delta, MapDelta, MapValue},
|
||||||
event::InternalDiff,
|
event::InternalDiff,
|
||||||
op::{RichOp, SliceRange, SliceRanges},
|
op::{RichOp, SliceRange, SliceRanges},
|
||||||
span::{HasId, HasLamport},
|
span::{HasId, HasLamport},
|
||||||
stable_pos::AbsolutePosition,
|
|
||||||
version::Frontiers,
|
version::Frontiers,
|
||||||
InternalString, VersionVector,
|
InternalString, VersionVector,
|
||||||
};
|
};
|
||||||
|
@ -462,7 +462,7 @@ pub(crate) struct ListDiffCalculator {
|
||||||
tracker: Box<RichtextTracker>,
|
tracker: Box<RichtextTracker>,
|
||||||
}
|
}
|
||||||
impl ListDiffCalculator {
|
impl ListDiffCalculator {
|
||||||
pub(crate) fn get_id_latest_pos(&self, id: ID) -> Option<crate::stable_pos::AbsolutePosition> {
|
pub(crate) fn get_id_latest_pos(&self, id: ID) -> Option<crate::cursor::AbsolutePosition> {
|
||||||
self.tracker.get_target_id_latest_index_at_new_version(id)
|
self.tracker.get_target_id_latest_index_at_new_version(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ use crate::{
|
||||||
richtext::{richtext_state::PosType, RichtextState, StyleOp, TextStyleInfoFlag},
|
richtext::{richtext_state::PosType, RichtextState, StyleOp, TextStyleInfoFlag},
|
||||||
tree::tree_op::TreeOp,
|
tree::tree_op::TreeOp,
|
||||||
},
|
},
|
||||||
|
cursor::{Cursor, Side},
|
||||||
delta::{DeltaItem, StyleMeta, TreeDiffItem, TreeExternalDiff},
|
delta::{DeltaItem, StyleMeta, TreeDiffItem, TreeExternalDiff},
|
||||||
op::ListSlice,
|
op::ListSlice,
|
||||||
stable_pos::{Cursor, Side},
|
|
||||||
state::{ContainerState, State, TreeParentId},
|
state::{ContainerState, State, TreeParentId},
|
||||||
txn::EventHint,
|
txn::EventHint,
|
||||||
utils::{string_slice::StringSlice, utf16::count_utf16_len},
|
utils::{string_slice::StringSlice, utf16::count_utf16_len},
|
||||||
|
|
|
@ -15,10 +15,10 @@ pub use handler::{BasicHandler, HandlerTrait, ListHandler, MapHandler, TextHandl
|
||||||
pub use loro::LoroDoc;
|
pub use loro::LoroDoc;
|
||||||
pub use oplog::OpLog;
|
pub use oplog::OpLog;
|
||||||
pub use state::DocState;
|
pub use state::DocState;
|
||||||
|
pub mod cursor;
|
||||||
pub mod loro;
|
pub mod loro;
|
||||||
pub mod obs;
|
pub mod obs;
|
||||||
pub mod oplog;
|
pub mod oplog;
|
||||||
pub mod stable_pos;
|
|
||||||
pub mod txn;
|
pub mod txn;
|
||||||
|
|
||||||
pub mod change;
|
pub mod change;
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
||||||
idx::ContainerIdx, list::list_op::InnerListOp, richtext::config::StyleConfigMap,
|
idx::ContainerIdx, list::list_op::InnerListOp, richtext::config::StyleConfigMap,
|
||||||
IntoContainerId,
|
IntoContainerId,
|
||||||
},
|
},
|
||||||
|
cursor::{AbsolutePosition, CannotFindRelativePosition, Cursor, PosQueryResult},
|
||||||
dag::DagUtils,
|
dag::DagUtils,
|
||||||
encoding::{
|
encoding::{
|
||||||
decode_snapshot, export_snapshot, parse_header_and_body, EncodeMode, ParsedHeaderAndBody,
|
decode_snapshot, export_snapshot, parse_header_and_body, EncodeMode, ParsedHeaderAndBody,
|
||||||
|
@ -30,7 +31,6 @@ use crate::{
|
||||||
id::PeerID,
|
id::PeerID,
|
||||||
op::InnerContent,
|
op::InnerContent,
|
||||||
oplog::dag::FrontiersNotIncluded,
|
oplog::dag::FrontiersNotIncluded,
|
||||||
stable_pos::{AbsolutePosition, CannotFindRelativePosition, Cursor, PosQueryResult},
|
|
||||||
version::Frontiers,
|
version::Frontiers,
|
||||||
HandlerTrait, InternalString, LoroError, VersionVector,
|
HandlerTrait, InternalString, LoroError, VersionVector,
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
idx::ContainerIdx, list::list_op::ListOp, map::MapSet, richtext::config::StyleConfigMap,
|
idx::ContainerIdx, list::list_op::ListOp, map::MapSet, richtext::config::StyleConfigMap,
|
||||||
tree::tree_op::TreeOp, ContainerIdRaw,
|
tree::tree_op::TreeOp, ContainerIdRaw,
|
||||||
},
|
},
|
||||||
|
cursor::Cursor,
|
||||||
delta::DeltaItem,
|
delta::DeltaItem,
|
||||||
encoding::{StateSnapshotDecodeContext, StateSnapshotEncoder},
|
encoding::{StateSnapshotDecodeContext, StateSnapshotEncoder},
|
||||||
event::{Diff, EventTriggerKind, Index, InternalContainerDiff, InternalDiff},
|
event::{Diff, EventTriggerKind, Index, InternalContainerDiff, InternalDiff},
|
||||||
|
@ -21,7 +22,6 @@ use crate::{
|
||||||
handler::ValueOrHandler,
|
handler::ValueOrHandler,
|
||||||
id::PeerID,
|
id::PeerID,
|
||||||
op::{ListSlice, Op, RawOp, RawOpContent},
|
op::{ListSlice, Op, RawOp, RawOpContent},
|
||||||
stable_pos::Cursor,
|
|
||||||
txn::Transaction,
|
txn::Transaction,
|
||||||
version::Frontiers,
|
version::Frontiers,
|
||||||
ContainerDiff, ContainerType, DocDiff, InternalString, LoroValue,
|
ContainerDiff, ContainerType, DocDiff, InternalString, LoroValue,
|
||||||
|
@ -1095,7 +1095,7 @@ impl DocState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if matches!(pos.side, crate::stable_pos::Side::Left) {
|
if matches!(pos.side, crate::cursor::Side::Left) {
|
||||||
return Some(0);
|
return Some(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use loro_internal::{
|
||||||
change::Lamport,
|
change::Lamport,
|
||||||
configure::{StyleConfig, StyleConfigMap},
|
configure::{StyleConfig, StyleConfigMap},
|
||||||
container::{richtext::ExpandType, ContainerID},
|
container::{richtext::ExpandType, ContainerID},
|
||||||
|
cursor::{self, Side},
|
||||||
encoding::ImportBlobMetadata,
|
encoding::ImportBlobMetadata,
|
||||||
event::Index,
|
event::Index,
|
||||||
handler::{
|
handler::{
|
||||||
|
@ -12,7 +13,6 @@ use loro_internal::{
|
||||||
},
|
},
|
||||||
id::{Counter, TreeID, ID},
|
id::{Counter, TreeID, ID},
|
||||||
obs::SubID,
|
obs::SubID,
|
||||||
stable_pos::{self, Side},
|
|
||||||
version::Frontiers,
|
version::Frontiers,
|
||||||
ContainerType, DiffEvent, HandlerTrait, LoroDoc, LoroValue,
|
ContainerType, DiffEvent, HandlerTrait, LoroDoc, LoroValue,
|
||||||
VersionVector as InternalVersionVector,
|
VersionVector as InternalVersionVector,
|
||||||
|
@ -136,8 +136,8 @@ extern "C" {
|
||||||
pub type JsImportBlobMetadata;
|
pub type JsImportBlobMetadata;
|
||||||
#[wasm_bindgen(typescript_type = "Side")]
|
#[wasm_bindgen(typescript_type = "Side")]
|
||||||
pub type JsSide;
|
pub type JsSide;
|
||||||
#[wasm_bindgen(typescript_type = "{ update?: StablePosition, offset: number, side: Side }")]
|
#[wasm_bindgen(typescript_type = "{ update?: Cursor, offset: number, side: Side }")]
|
||||||
pub type JsStablePosQueryAns;
|
pub type JsCursorQueryAns;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod observer {
|
mod observer {
|
||||||
|
@ -1135,14 +1135,14 @@ impl Loro {
|
||||||
/// expect(ans.offset).toBe(1);
|
/// expect(ans.offset).toBe(1);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn getCursorPos(&self, stable_pos: &StablePosition) -> JsResult<JsStablePosQueryAns> {
|
pub fn getCursorPos(&self, cursor: &Cursor) -> JsResult<JsCursorQueryAns> {
|
||||||
let ans = self
|
let ans = self
|
||||||
.0
|
.0
|
||||||
.query_pos(&stable_pos.pos)
|
.query_pos(&cursor.pos)
|
||||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||||
|
|
||||||
let obj = Object::new();
|
let obj = Object::new();
|
||||||
let update = ans.update.map(|u| StablePosition { pos: u });
|
let update = ans.update.map(|u| Cursor { pos: u });
|
||||||
if let Some(update) = update {
|
if let Some(update) = update {
|
||||||
let update_value: JsValue = update.into();
|
let update_value: JsValue = update.into();
|
||||||
Reflect::set(&obj, &JsValue::from_str("update"), &update_value)?;
|
Reflect::set(&obj, &JsValue::from_str("update"), &update_value)?;
|
||||||
|
@ -1505,7 +1505,7 @@ impl LoroText {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(skip_typescript)]
|
#[wasm_bindgen(skip_typescript)]
|
||||||
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<StablePosition> {
|
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<Cursor> {
|
||||||
let mut side_value = Side::Middle;
|
let mut side_value = Side::Middle;
|
||||||
if side.is_truthy() {
|
if side.is_truthy() {
|
||||||
let num = side.as_f64().expect("Side must be -1 | 0 | 1");
|
let num = side.as_f64().expect("Side must be -1 | 0 | 1");
|
||||||
|
@ -1513,7 +1513,7 @@ impl LoroText {
|
||||||
}
|
}
|
||||||
self.handler
|
self.handler
|
||||||
.get_cursor(pos, side_value)
|
.get_cursor(pos, side_value)
|
||||||
.map(|pos| StablePosition { pos })
|
.map(|pos| Cursor { pos })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2131,7 +2131,7 @@ impl LoroList {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(skip_typescript)]
|
#[wasm_bindgen(skip_typescript)]
|
||||||
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<StablePosition> {
|
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<Cursor> {
|
||||||
let mut side_value = Side::Middle;
|
let mut side_value = Side::Middle;
|
||||||
if side.is_truthy() {
|
if side.is_truthy() {
|
||||||
let num = side.as_f64().expect("Side must be -1 | 0 | 1");
|
let num = side.as_f64().expect("Side must be -1 | 0 | 1");
|
||||||
|
@ -2139,7 +2139,7 @@ impl LoroList {
|
||||||
}
|
}
|
||||||
self.handler
|
self.handler
|
||||||
.get_cursor(pos, side_value)
|
.get_cursor(pos, side_value)
|
||||||
.map(|pos| StablePosition { pos })
|
.map(|pos| Cursor { pos })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2569,12 +2569,12 @@ impl Default for LoroTree {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct StablePosition {
|
pub struct Cursor {
|
||||||
pos: stable_pos::Cursor,
|
pos: cursor::Cursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl StablePosition {
|
impl Cursor {
|
||||||
pub fn containerId(&self) -> JsContainerID {
|
pub fn containerId(&self) -> JsContainerID {
|
||||||
let js_value: JsValue = self.pos.container.to_string().into();
|
let js_value: JsValue = self.pos.container.to_string().into();
|
||||||
JsContainerID::from(js_value)
|
JsContainerID::from(js_value)
|
||||||
|
@ -2592,9 +2592,9 @@ impl StablePosition {
|
||||||
|
|
||||||
pub fn side(&self) -> JsSide {
|
pub fn side(&self) -> JsSide {
|
||||||
JsValue::from(match self.pos.side {
|
JsValue::from(match self.pos.side {
|
||||||
stable_pos::Side::Left => -1,
|
cursor::Side::Left => -1,
|
||||||
stable_pos::Side::Middle => 0,
|
cursor::Side::Middle => 0,
|
||||||
stable_pos::Side::Right => 1,
|
cursor::Side::Right => 1,
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
@ -2603,10 +2603,9 @@ impl StablePosition {
|
||||||
self.pos.encode()
|
self.pos.encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(data: &[u8]) -> JsResult<StablePosition> {
|
pub fn decode(data: &[u8]) -> JsResult<Cursor> {
|
||||||
let pos =
|
let pos = cursor::Cursor::decode(data).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||||
stable_pos::Cursor::decode(data).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
Ok(Cursor { pos })
|
||||||
Ok(StablePosition { pos })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2940,19 +2939,19 @@ export interface ImportBlobMetadata {
|
||||||
|
|
||||||
interface LoroText {
|
interface LoroText {
|
||||||
/**
|
/**
|
||||||
* Get a stable position representing the cursor position.
|
* Get the cursor position at the given pos.
|
||||||
*
|
*
|
||||||
* When expressing the position of a cursor, using "index" can be unstable
|
* When expressing the position of a cursor, using "index" can be unstable
|
||||||
* because the cursor's position may change due to other deletions and insertions,
|
* because the cursor's position may change due to other deletions and insertions,
|
||||||
* requiring updates with each edit. To stably represent a position or range within
|
* requiring updates with each edit. To stably represent a position or range within
|
||||||
* a list structure, we can utilize the ID of each item/character on List CRDT or
|
* a list structure, we can utilize the ID of each item/character on List CRDT or
|
||||||
* Text CRDT for expression.
|
* Text CRDT for expression.
|
||||||
*
|
*
|
||||||
* Loro optimizes State metadata by not storing the IDs of deleted elements. This
|
* Loro optimizes State metadata by not storing the IDs of deleted elements. This
|
||||||
* approach complicates tracking cursors since they rely on these IDs. The solution
|
* approach complicates tracking cursors since they rely on these IDs. The solution
|
||||||
* recalculates position by replaying relevant history to update stable positions
|
* recalculates position by replaying relevant history to update cursors
|
||||||
* accurately. To minimize the performance impact of history replay, the system
|
* accurately. To minimize the performance impact of history replay, the system
|
||||||
* updates cursor info to reference only the IDs of currently present elements,
|
* updates cursor info to reference only the IDs of currently present elements,
|
||||||
* thereby reducing the need for replay.
|
* thereby reducing the need for replay.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -2973,24 +2972,24 @@ interface LoroText {
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
getCursor(pos: number, side?: Side): StablePosition | undefined;
|
getCursor(pos: number, side?: Side): Cursor | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoroList {
|
interface LoroList {
|
||||||
/**
|
/**
|
||||||
* Get a stable position representing the cursor position.
|
* Get the cursor position at the given pos.
|
||||||
*
|
*
|
||||||
* When expressing the position of a cursor, using "index" can be unstable
|
* When expressing the position of a cursor, using "index" can be unstable
|
||||||
* because the cursor's position may change due to other deletions and insertions,
|
* because the cursor's position may change due to other deletions and insertions,
|
||||||
* requiring updates with each edit. To stably represent a position or range within
|
* requiring updates with each edit. To stably represent a position or range within
|
||||||
* a list structure, we can utilize the ID of each item/character on List CRDT or
|
* a list structure, we can utilize the ID of each item/character on List CRDT or
|
||||||
* Text CRDT for expression.
|
* Text CRDT for expression.
|
||||||
*
|
*
|
||||||
* Loro optimizes State metadata by not storing the IDs of deleted elements. This
|
* Loro optimizes State metadata by not storing the IDs of deleted elements. This
|
||||||
* approach complicates tracking cursors since they rely on these IDs. The solution
|
* approach complicates tracking cursors since they rely on these IDs. The solution
|
||||||
* recalculates position by replaying relevant history to update stable positions
|
* recalculates position by replaying relevant history to update cursors
|
||||||
* accurately. To minimize the performance impact of history replay, the system
|
* accurately. To minimize the performance impact of history replay, the system
|
||||||
* updates cursor info to reference only the IDs of currently present elements,
|
* updates cursor info to reference only the IDs of currently present elements,
|
||||||
* thereby reducing the need for replay.
|
* thereby reducing the need for replay.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -3011,7 +3010,7 @@ interface LoroList {
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
getCursor(pos: number, side?: Side): StablePosition | undefined;
|
getCursor(pos: number, side?: Side): Cursor | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Side = -1 | 0 | 1;
|
export type Side = -1 | 0 | 1;
|
||||||
|
|
|
@ -3,13 +3,13 @@ use either::Either;
|
||||||
use event::{DiffEvent, Subscriber};
|
use event::{DiffEvent, Subscriber};
|
||||||
use loro_internal::change::Timestamp;
|
use loro_internal::change::Timestamp;
|
||||||
use loro_internal::container::IntoContainerId;
|
use loro_internal::container::IntoContainerId;
|
||||||
|
use loro_internal::cursor::CannotFindRelativePosition;
|
||||||
|
use loro_internal::cursor::Cursor;
|
||||||
|
use loro_internal::cursor::PosQueryResult;
|
||||||
|
use loro_internal::cursor::Side;
|
||||||
use loro_internal::encoding::ImportBlobMetadata;
|
use loro_internal::encoding::ImportBlobMetadata;
|
||||||
use loro_internal::handler::HandlerTrait;
|
use loro_internal::handler::HandlerTrait;
|
||||||
use loro_internal::handler::ValueOrHandler;
|
use loro_internal::handler::ValueOrHandler;
|
||||||
use loro_internal::stable_pos::CannotFindRelativePosition;
|
|
||||||
use loro_internal::stable_pos::Cursor;
|
|
||||||
use loro_internal::stable_pos::PosQueryResult;
|
|
||||||
use loro_internal::stable_pos::Side;
|
|
||||||
use loro_internal::LoroDoc as InnerLoroDoc;
|
use loro_internal::LoroDoc as InnerLoroDoc;
|
||||||
use loro_internal::OpLog;
|
use loro_internal::OpLog;
|
||||||
|
|
||||||
|
@ -596,7 +596,7 @@ impl LoroList {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use loro::LoroDoc;
|
/// use loro::LoroDoc;
|
||||||
/// use loro_internal::stable_pos::Side;
|
/// use loro_internal::cursor::Side;
|
||||||
///
|
///
|
||||||
/// let doc = LoroDoc::new();
|
/// let doc = LoroDoc::new();
|
||||||
/// let list = doc.get_list("list");
|
/// let list = doc.get_list("list");
|
||||||
|
|
|
@ -49,7 +49,7 @@ fn readme_basic() {
|
||||||
#[test]
|
#[test]
|
||||||
fn get_list_cursor_example() {
|
fn get_list_cursor_example() {
|
||||||
use loro::LoroDoc;
|
use loro::LoroDoc;
|
||||||
use loro_internal::stable_pos::Side;
|
use loro_internal::cursor::Side;
|
||||||
|
|
||||||
let doc = LoroDoc::new();
|
let doc = LoroDoc::new();
|
||||||
let list = doc.get_list("list");
|
let list = doc.get_list("list");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { Delta, Loro, TextDiff } from "../src";
|
import { Delta, Loro, TextDiff } from "../src";
|
||||||
import { OpId, setDebug } from "loro-wasm";
|
import { Cursor, OpId, setDebug } from "loro-wasm";
|
||||||
|
|
||||||
describe("richtext", () => {
|
describe("richtext", () => {
|
||||||
it("mark", () => {
|
it("mark", () => {
|
||||||
|
@ -237,12 +237,18 @@ describe("richtext", () => {
|
||||||
expect(ans.update).toBeUndefined();
|
expect(ans.update).toBeUndefined();
|
||||||
}
|
}
|
||||||
text.insert(0, "abc");
|
text.insert(0, "abc");
|
||||||
|
const bytes = pos0!.encode();
|
||||||
|
// Sending pos0 over the network
|
||||||
|
const pos0decoded = Cursor.decode(bytes);
|
||||||
|
const docA = new Loro();
|
||||||
|
docA.import(doc.exportFrom());
|
||||||
{
|
{
|
||||||
const ans = doc.getCursorPos(pos0!);
|
const ans = docA.getCursorPos(pos0decoded!);
|
||||||
expect(ans.side).toBe(0);
|
expect(ans.side).toBe(0);
|
||||||
expect(ans.offset).toBe(3);
|
expect(ans.offset).toBe(3);
|
||||||
expect(ans.update).toBeUndefined();
|
expect(ans.update).toBeUndefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "1" is removed from the text, the stable position should be updated
|
// If "1" is removed from the text, the stable position should be updated
|
||||||
text.delete(3, 1); // remove "1", "abc23"
|
text.delete(3, 1); // remove "1", "abc23"
|
||||||
doc.commit();
|
doc.commit();
|
||||||
|
|
Loading…
Reference in a new issue