Skip to content

feat: group api for UndoManager#720

Merged
zxch3n merged 31 commits into
loro-dev:mainfrom
synoet:synoet/manual-checkpoint-undo
May 20, 2025
Merged

feat: group api for UndoManager#720
zxch3n merged 31 commits into
loro-dev:mainfrom
synoet:synoet/manual-checkpoint-undo

Conversation

@synoet
Copy link
Copy Markdown
Contributor

@synoet synoet commented Apr 28, 2025

Adds a new api to UndoManager to support grouping together changes into ideally one undo item.

UndoManager::group_start(): will start a new group of changes, all subsequent changes will be merged into a new item on the undo stack. If we receive remote changes, we determine wether or not they are conflicting. If the remote changes are conflicting we split the undo item and close the group. If there are no conflict in changed container ids we continue the group merge.

UndoManager::group_end(): ends the current group, calling UndoManager::undo() after this will undo all changes that occurred during the group.

  • Introduces new semantics for handling remote imports. If a remote import happens we compare ContainerID's from the remote import and the last item on the undo stack, if there is no overlap we deem it safe to continue merging into the last undo item regardless of the remote import. If there are conflicts it behaves as it did previously.
                                               ┌────────────────┐                                     
                                               │ group_start()  │                                     
                                               └────────────────┘                                     
                                                        │                                             
 UndoStack                                              │                                             
 ┌─────────────────┐                            make local change                                     
 │ ┌─────────────┐ │      push new item        ┌────────────────┐                                     
 │ │   undo_1    │◀│─ ─ ─ to undo stack ─ ─ ─ ─│    commit()    │                                     
 │ └─────────────┘ │                           └────────────────┘             ┌───────────┐           
 │        ▲        │                                    │                     │group_end()│◀ ─ ─ ─ ─ ┐
 │        │        │                            make local change             └───────────┘           
 │        │        │       merge with          ┌────────────────┐                                    │
 │        └ ─ ─ ─ ─│─ ─ ─ previous item ─ ─ ─ ─│    commit()    │                                     
 │        │        │      in same group        └────────────────┘                               Λ    │
 │                 │                                    │                                      ╱ ╲    
 │        │        │                                    │                                   ─▶▕ Y ▏─ ┘
 │                 │                          import remote change      ┌ ─ ─ ─ ─ ─ ─ ─ ┐  │   ╲ ╱    
 │        │        │                           ┌────────────────┐          does import          V     
 │                 │                           │    import()    │─ ─ ─▶ │  affect last  │─ ┤          
 │        │        │                           └────────────────┘          undo item?           Λ     
 │                 │    Λ                               │               └ ─ ─ ─ ─ ─ ─ ─ ┘  │   ╱ ╲    
 │        │        │   ╱ ╲                              │                                   ─▶▕ N ▏   
 │         ─ ─ ─ ─ ┼ ─▕ Y ▏◀─ ─ ─ ─ ─                   ▼                                      ╲ ╱    
 │                 │   ╲ ╱           │          make local change                               V     
 │                 │    V    ┌ ─ ─ ─ ─ ─ ─ ─ ┐ ┌────────────────┐                                     
 │                 │          is group_active ─│    commit()    │                                     
 │                 │         └ ─ ─ ─ ─ ─ ─ ─ ┘ └────────────────┘                                     
 │ ┌─────────────┐ │                 │                                                                
 │ │   undo_2    │◀┼───┐       Λ                                                                      
 │ └─────────────┘ │   │      ╱ ╲    │                                                                
 │                 │   └─────▕ N ▏◀ ─                                                                 
 │            push new item   ╲ ╱                                                                     
 │                 │           V                                                                                                                                                
 └─────────────────┘                                                                                  

Example usage from tests:

    const doc = new LoroDoc()
    const undoManager = new UndoManager(doc, {});
    const text = doc.getText("text");

    undoManager.groupStart();

    text.update("hello", undefined);
    doc.commit();

    text.update("world", undefined);
    doc.commit();

    undoManager.groupEnd();

    undoManager.undo();

    expect(text.toString()).toBe("");

@synoet synoet marked this pull request as ready for review April 28, 2025 20:43
Copy link
Copy Markdown
Member

@zxch3n zxch3n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@synoet synoet changed the title feat: support optional manual checkpointing for UndoManager feat: group api for UndoManager May 17, 2025
Comment thread crates/loro-internal/src/undo.rs Outdated
Comment thread crates/loro-internal/src/undo.rs Outdated
Comment thread crates/loro-internal/src/undo.rs Outdated
Comment thread crates/loro-wasm/src/lib.rs
Comment thread crates/loro-wasm/src/lib.rs Outdated
zxch3n and others added 6 commits May 20, 2025 10:53
* docs: add intro for loro-inspector

* docs: refine structure
* ci: fix

* ci: use the right install command
- Surface the undo_stack and redo_stack depths
- Add undo_count() and redo_count() checks to unit tests
zxch3n and others added 7 commits May 20, 2025 10:53
* refactor: hide tracing logs behind 'logging' feature

* fix: grammar err
* feat: add redact to wasm

- Implemented `redact_json_updates` function to redact sensitive content in JSON updates.
- Added tests for `redactJsonUpdates` to ensure sensitive content is properly redacted.
@zxch3n zxch3n merged commit 70a3bf3 into loro-dev:main May 20, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants