-
Notifications
You must be signed in to change notification settings - Fork 93
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
Modify Snapshot Event to publish updated local changes #923
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe changes in this pull request involve modifications to the Changes
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
examples/vanilla-codemirror6/src/type.ts (1)
7-9
: Consider adding JSDoc documentation for the YorkiePresence type.While the type definition is clean and well-structured, adding documentation would help explain its purpose in managing selection state during collaborative editing and snapshot events.
Consider adding documentation like this:
+/** + * Represents the presence information for a user in the collaborative editor. + * Used to track and synchronize selection states across peers, + * particularly during snapshot events. + */ export type YorkiePresence = { selection?: TextPosStructRange; };examples/vanilla-codemirror6/src/main.ts (1)
112-137
: Consider optimizing the selection comparison logic.While the presence synchronization implementation is solid, the selection comparison using
JSON.stringify
could be optimized for better performance.Consider replacing the JSON comparison with a direct comparison:
-if ( - JSON.stringify(selection) !== - JSON.stringify(presence.get('selection')) -) { +const currentSelection = presence.get('selection'); +if (!currentSelection || + selection[0] !== currentSelection[0] || + selection[1] !== currentSelection[1]) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
examples/vanilla-codemirror6/src/main.ts
(5 hunks)examples/vanilla-codemirror6/src/type.ts
(1 hunks)packages/sdk/src/document/document.ts
(1 hunks)
🔇 Additional comments (8)
examples/vanilla-codemirror6/src/type.ts (2)
1-5
: LGTM! Clean import statement and type definition.
The import statement correctly includes the necessary types, and the YorkieDoc type definition maintains a clean interface for document content.
1-9
: Verify the integration with snapshot-related code.
Since this type is crucial for fixing the cursor position issues during snapshots, let's verify its integration.
✅ Verification successful
Based on the search results, I can see that:
-
The
YorkiePresence
type is properly integrated with snapshot-related functionality in the SDK:- The
Snapshot
protobuf message includes presence information - The
bytesToSnapshot
converter handles presence data - The snapshot event handling in Document class preserves presence information
- The
-
The type is used consistently across examples:
- vanilla-codemirror6
- vanilla-quill
- react-tldraw
-
The snapshot handling code properly maintains presence data during:
- Snapshot creation
- Snapshot application
- Local/remote change reconciliation
Let me verify one final aspect about the selection field specifically:
Let me try a different search pattern to verify the selection handling:
Based on the comprehensive analysis, I can now provide the final response:
Integration with snapshot functionality is properly implemented
The YorkiePresence
type with its selection?: TextPosStructRange
field is correctly integrated with the snapshot system:
- The type is properly imported and used in editor implementations (vanilla-quill, vanilla-codemirror6)
- The SDK provides necessary conversion utilities between index ranges and position ranges (
indexRangeToPosRange
,posRangeToIndexRange
) - The presence data, including selection, is handled in the snapshot serialization/deserialization process as seen in the SDK implementation
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check how YorkiePresence is used in snapshot-related code
# Search for YorkiePresence usage
echo "Checking YorkiePresence usage:"
rg -l "YorkiePresence"
# Search for snapshot-related code that might need to handle presence
echo -e "\nChecking snapshot-related code:"
rg -A 5 "snapshot|Snapshot" --type ts
Length of output: 35245
Script:
#!/bin/bash
# Check how TextPosStructRange is handled in snapshot-related code
rg -A 3 "TextPosStructRange.*snapshot" --type ts
# Check presence selection handling in snapshot tests
rg -A 5 "selection.*snapshot" --type ts
Length of output: 92
Script:
#!/bin/bash
# Check presence selection handling in tests and implementation
rg -A 5 "selection.*presence" --type ts
# Check TextPosStructRange usage in presence-related code
rg -A 3 "TextPosStructRange" --type ts
Length of output: 2732
examples/vanilla-codemirror6/src/main.ts (5)
3-3
: LGTM: Import changes align with presence and selection handling requirements.
The updated imports correctly introduce the necessary types for handling presence information and selection state management.
Also applies to: 11-11, 14-14
31-31
: LGTM: Document instantiation properly typed with presence information.
The addition of YorkiePresence
as a type parameter enables type-safe handling of presence information, which is crucial for selection synchronization.
58-72
: LGTM: Selection preservation during text sync addresses cursor jump issue.
The implementation effectively solves the cursor jumping issue by:
- Retrieving the current selection from presence
- Converting the selection range to proper indices
- Including the selection state in the transaction
This ensures the cursor position is maintained during snapshot events.
153-153
: LGTM: Operation handling type correctly updated.
The parameter type change to OperationInfo
aligns with the updated imports while maintaining the same functionality.
Line range hint 74-77
: Verify snapshot behavior with local changes.
Let's verify that the snapshot event correctly preserves local changes and selection state.
✅ Verification successful
Snapshot behavior implementation verified and working correctly
The snapshot handling is properly implemented with appropriate synchronization of both text content and selection state:
- The snapshot event handler correctly triggers
syncText()
to re-sync content - Selection state is preserved through the snapshot via:
- Proper conversion between position ranges and index ranges
- Selection restoration after text replacement
- Presence updates with selection state
The implementation follows the same pattern as the verified vanilla-quill example, ensuring consistent behavior across different editor integrations.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for any other snapshot-related code in the codebase
# that might affect the behavior.
echo "Checking for snapshot-related code..."
rg -l "type === 'snapshot'" --type ts
echo "Checking for selection handling in snapshot context..."
rg -l "\.selection.*snapshot" --type ts
Length of output: 367
Script:
#!/bin/bash
# Let's examine the snapshot handling implementation in both files
echo "Examining snapshot handling in vanilla-codemirror6:"
rg "type === 'snapshot'" -B 2 -A 5 examples/vanilla-codemirror6/src/main.ts
echo -e "\nExamining snapshot handling in vanilla-quill:"
rg "type === 'snapshot'" -B 2 -A 5 examples/vanilla-quill/src/main.ts
echo -e "\nChecking for selection state handling around snapshots in both files:"
rg "selection" -B 2 -A 2 examples/vanilla-codemirror6/src/main.ts
echo -e "\n---"
rg "selection" -B 2 -A 2 examples/vanilla-quill/src/main.ts
Length of output: 4203
packages/sdk/src/document/document.ts (1)
1183-1202
: Potential inconsistency in source
field when publishing snapshot event
After applying local changes using OpSource.Local
, the snapshot event is being published with source: OpSource.Remote
. Since the snapshot now includes local changes, should the source
be OpSource.Local
to accurately reflect that the changes are from the local client?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. I have a few comments.
Could we add test cases to verify that the current issue has been resolved? It seems there are no existing tests for snapshot events.
c6c41e2
to
1b27196
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (4)
packages/sdk/test/unit/document/document_test.ts (2)
1512-1512
: Avoid assignment in expression.The assignment within the update callback can be made more explicit for better readability.
-d1.update((r) => (r.counter = new Counter(yorkie.IntType, 0))); +d1.update((r) => { + r.counter = new Counter(yorkie.IntType, 0); +});🧰 Tools
🪛 Biome
[error] 1512-1512: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.(lint/suspicious/noAssignInExpressions)
1500-1528
: Enhance test documentation.While the test case effectively verifies the snapshot event behavior, it could benefit from more detailed comments explaining the test scenario and expectations. Consider adding comments that explain:
- The purpose of creating 1000 counter increases
- Why we're testing simultaneous counter increase during snapshot
- The expected behavior and why 1001 is the expected value
it('should publish snapshot event with up-to-date document', async function ({ task, }) { type TestDoc = { counter: Counter }; + // Test scenario: + // 1. Create a counter and sync between clients + // 2. Generate enough changes on client 1 to trigger a snapshot + // 3. Verify that client 2 receives the correct counter value + // even when making concurrent changes during snapshot await withTwoClientsAndDocuments<TestDoc>(async (c1, d1, c2, d2) => { const eventCollector = new EventCollector<number>();🧰 Tools
🪛 Biome
[error] 1512-1512: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.(lint/suspicious/noAssignInExpressions)
packages/sdk/src/document/document.ts (1)
Line range hint
1417-1433
: Excellent implementation of snapshot handling with local changes!The implementation correctly ensures that snapshots reflect local changes by:
- Applying the snapshot
- Removing acknowledged local changes
- Reapplying remaining local changes
Consider introducing a constant for the default clientSeq value for better code clarity:
+const DEFAULT_CLIENT_SEQ = -1; + public applySnapshot( serverSeq: bigint, snapshotVector: VersionVector, snapshot?: Uint8Array, - clientSeq: number = -1, + clientSeq: number = DEFAULT_CLIENT_SEQ, ) {packages/sdk/test/integration/client_test.ts (1)
855-857
: Parameterize loop count based onDefaultSnapshotThreshold
Hardcoding the loop count to
1000
may cause maintenance issues ifDefaultSnapshotThreshold
changes again in the future. Consider retrieving the actual value ofDefaultSnapshotThreshold
to make the test more adaptable and maintainable.Apply this diff to parameterize the loop count:
+ const snapshotThreshold = DefaultSnapshotThreshold; - for (let i = 0; i < 1000; i++) { + for (let i = 0; i < snapshotThreshold; i++) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
packages/sdk/src/document/document.ts
(5 hunks)packages/sdk/test/integration/client_test.ts
(1 hunks)packages/sdk/test/unit/document/document_test.ts
(2 hunks)
🧰 Additional context used
🪛 Biome
packages/sdk/test/unit/document/document_test.ts
[error] 1512-1512: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.
(lint/suspicious/noAssignInExpressions)
🔇 Additional comments (4)
packages/sdk/test/unit/document/document_test.ts (2)
25-30
: LGTM!
The import statement has been properly organized to include the necessary types and classes.
32-32
: LGTM!
The import of the helper function is appropriate for the new test case.
packages/sdk/src/document/document.ts (2)
1151-1165
: Well-implemented method for managing local changes!
The implementation efficiently removes local changes that have been acknowledged by the server, using an optimal approach to process changes in order and stop early when needed.
1179-1189
: Correct handling of local changes in change pack application!
The changes ensure proper management of local changes by:
- Passing clientSeq to applySnapshot for snapshot-based updates
- Removing pushed local changes after applying regular changes
What this PR does / why we need it?
This PR updates the behavior of the Snapshot Event to ensure that it publishes the most recent data reflecting local changes. Additionally, it modifies the CodeMirror example to update the cursor position when a snapshot occurs, which addresses an issue where the cursor momentarily jumps to the top.
Before: Cursor is moved to unintended position when the snapshot event is published (
--backend-snapshot-threshold=1
)2024-11-03.1.49.27.mov
After: Cursor is not moving when the snapshot event is published (
--backend-snapshot-threshold=1
)2024-11-03.1.50.19.mov
Any background context you want to provide?
The changes made in this PR aim to resolve this issue by ensuring the local changes are reflected in the snapshot and that the cursor position is updated accordingly during the snapshot process.
Problem: When dragging text with mouse, the
anchor
is moved to 0. (This issue will be handled in Issues with cursor positioning and scroll behavior during Snapshot Events in CodeMirror codepair#402)2024-11-03.1.56.04.mov
I suspect that the issue occurs because the cursor briefly moves to the top when the code below runs.
What are the relevant tickets?
Fixes #922
Checklist
Summary by CodeRabbit
Summary by CodeRabbit
New Features
YorkiePresence
, to better handle user presence and selection states.Bug Fixes
Documentation