-
Notifications
You must be signed in to change notification settings - Fork 107
Implement reverse EditOperation for Text #1126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
9834672
b7f0e7e
5e734b5
157271b
3f7add7
1981f74
d6211b3
fdb81f2
cf8927a
23379ab
fce5d95
8aabf3f
7efa55f
3bd7e20
dda181a
a3b585d
000e487
bf0b70e
53eef57
4d2d0e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -597,14 +597,20 @@ export class RGATreeSplit<T extends RGATreeSplitValue> implements GCParent { | |
| * @param range - range of RGATreeSplitNode | ||
| * @param editedAt - edited time | ||
| * @param value - value | ||
| * @returns `[RGATreeSplitPos, Array<GCPair>, Array<Change>]` | ||
| * @returns `[RGATreeSplitPos, Array<GCPair>, DataSize, Array<ValueChange<T>>, Array<T>]` | ||
| */ | ||
| public edit( | ||
| range: RGATreeSplitPosRange, | ||
| editedAt: TimeTicket, | ||
| value?: T, | ||
| versionVector?: VersionVector, | ||
| ): [RGATreeSplitPos, Array<GCPair>, DataSize, Array<ValueChange<T>>] { | ||
| ): [ | ||
| RGATreeSplitPos, | ||
| Array<GCPair>, | ||
| DataSize, | ||
| Array<ValueChange<T>>, | ||
| Array<T>, | ||
| ] { | ||
| const diff = { data: 0, meta: 0 }; | ||
|
|
||
| // 01. split nodes with from and to | ||
|
|
@@ -659,11 +665,13 @@ export class RGATreeSplit<T extends RGATreeSplitValue> implements GCParent { | |
|
|
||
| // 04. add removed node | ||
| const pairs: Array<GCPair> = []; | ||
| const removedValues: Array<T> = []; | ||
| for (const [, removedNode] of removedNodes) { | ||
| pairs.push({ parent: this, child: removedNode }); | ||
| removedValues.push(removedNode.getValue()); | ||
| } | ||
|
|
||
| return [caretPos, pairs, diff, changes]; | ||
| return [caretPos, pairs, diff, changes, removedValues]; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -787,6 +795,63 @@ export class RGATreeSplit<T extends RGATreeSplitValue> implements GCParent { | |
| return clone; | ||
| } | ||
|
|
||
| /** | ||
| * `normalizePos` converts a local position `(id, rel)` into a single | ||
| * absolute offset measured from the head `(0:0)` of the physical chain. | ||
| */ | ||
| public normalizePos(pos: RGATreeSplitPos): RGATreeSplitPos { | ||
| const index = this.posToIndex(pos, true); | ||
|
|
||
| return RGATreeSplitPos.of(this.getHead().getID(), index); | ||
| } | ||
|
|
||
| /** | ||
| * `refinePos` remaps the given pos to the current split chain. | ||
| * | ||
| * - Traverses the physical `next` chain (not `insNext`). | ||
| * - Counts only live characters: removed nodes are treated as length 0. | ||
| * - If the given offset exceeds the length of the current node, | ||
| * it moves forward through `next` nodes, subtracting lengths, | ||
| * until the offset fits in a live node. | ||
| * - If it runs out of nodes, it snaps to the end of the last node. | ||
| * | ||
| * Example: | ||
| * Before split: ["12345"](1:2:0), pos = (1:2:0, rel=5) | ||
| * After split : ["1"](1:2:0) - ["23"](1:2:1) - ["45"](1:2:3) | ||
| * refinePos(pos) -> (1:2:3, rel=2) | ||
| * | ||
| * Example: | ||
| * ["12"](1:2:0, live) and pos = (1:2:0, rel=4) | ||
| * refinePos(pos) -> points two chars after "12", | ||
| * i.e. advances into following nodes, skipping removed ones. | ||
| */ | ||
| public refinePos(pos: RGATreeSplitPos): RGATreeSplitPos { | ||
| let node = this.findFloorNode(pos.getID()); | ||
| if (!node) { | ||
| throw new YorkieError( | ||
| Code.ErrInvalidArgument, | ||
| `the node of the given id should be found: ${pos.getID().toTestString()}`, | ||
| ); | ||
| } | ||
|
|
||
| let offsetInPart = pos.getRelativeOffset(); | ||
| let partLen = node.getContentLength(); | ||
|
|
||
| while (offsetInPart > partLen) { | ||
| offsetInPart -= partLen; | ||
| const next: RGATreeSplitNode<T> | undefined = node!.getNext(); | ||
|
|
||
| if (!next) { | ||
| return RGATreeSplitPos.of(node.getID(), partLen); | ||
| } | ||
|
|
||
| node = next; | ||
| partLen = node.getLength(); | ||
| } | ||
|
|
||
| return RGATreeSplitPos.of(node.getID(), offsetInPart); | ||
| } | ||
|
Comment on lines
+844
to
+869
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Search for tests that verify refinePos behavior
rg -n "refinePos" --type=ts -A 5 -B 2Repository: yorkie-team/yorkie-js-sdk Length of output: 3764 🏁 Script executed: # Search for getContentLength and getLength definitions
rg -n "getContentLength\(\)|getLength\(\)" packages/sdk/src/document/crdt/rga_tree_split.ts --type=ts -B 2 -A 3Repository: yorkie-team/yorkie-js-sdk Length of output: 1498 🏁 Script executed: # Examine the RGATreeSplitNode class to understand these methods
ast-grep --pattern 'class RGATreeSplitNode {
$$$
}'Repository: yorkie-team/yorkie-js-sdk Length of output: 51 🏁 Script executed: # Search for findFloorNode to understand if it can return removed nodes
rg -n "findFloorNode" packages/sdk/src/document/crdt/rga_tree_split.ts --type=ts -A 10 -B 2Repository: yorkie-team/yorkie-js-sdk Length of output: 2734 🏁 Script executed: # Search for test cases that test refinePos with removed content
rg -n "refinePos" --type=ts -l | xargs grep -l "remov\|delete" | head -5Repository: yorkie-team/yorkie-js-sdk Length of output: 210 🏁 Script executed: # Search specifically in test files for refinePos tests
fd ".*\.test\.ts$|.*\.spec\.ts$" --type=f | xargs rg -l "refinePos" 2>/dev/null | head -3Repository: yorkie-team/yorkie-js-sdk Length of output: 51 Fix inconsistent length calculation for initial node in Line 838 uses When the initial node is removed, the current code incorrectly uses its full content length instead of treating it as 0. Change line 838 to use 🤖 Prompt for AI Agents |
||
|
|
||
| /** | ||
| * `toTestString` returns a String containing the meta data of the node | ||
| * for debugging purpose. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.