Skip to content

Commit 93fb2fd

Browse files
authored
Add UndoManager undo_count() and redo_count() (#725)
- Surface the undo_stack and redo_stack depths - Add undo_count() and redo_count() checks to unit tests
1 parent 87762a1 commit 93fb2fd

4 files changed

Lines changed: 51 additions & 0 deletions

File tree

crates/loro-ffi/src/undo.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ impl UndoManager {
3737
self.0.read().unwrap().can_redo()
3838
}
3939

40+
/// How many times the undo manager can undo.
41+
pub fn undo_count(&self) -> usize {
42+
self.0.read().unwrap().undo_count()
43+
}
44+
45+
/// How many times the undo manager can redo.
46+
pub fn redo_count(&self) -> usize {
47+
self.0.read().unwrap().redo_count()
48+
}
49+
4050
/// If a local event's origin matches the given prefix, it will not be recorded in the
4151
/// undo stack.
4252
pub fn add_exclude_origin_prefix(&self, prefix: &str) {

crates/loro-internal/src/undo.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,14 @@ impl UndoManager {
756756
!self.inner.lock().unwrap().redo_stack.is_empty()
757757
}
758758

759+
pub fn undo_count(&self) -> usize {
760+
self.inner.lock().unwrap().undo_stack.len()
761+
}
762+
763+
pub fn redo_count(&self) -> usize {
764+
self.inner.lock().unwrap().redo_stack.len()
765+
}
766+
759767
pub fn set_on_push(&self, on_push: Option<OnPush>) {
760768
self.inner.lock().unwrap().on_push = on_push;
761769
}

crates/loro/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,16 @@ impl UndoManager {
30283028
self.0.can_redo()
30293029
}
30303030

3031+
/// How many times the undo manager can undo.
3032+
pub fn undo_count(&self) -> usize {
3033+
self.0.undo_count()
3034+
}
3035+
3036+
/// How many times the undo manager can redo.
3037+
pub fn redo_count(&self) -> usize {
3038+
self.0.redo_count()
3039+
}
3040+
30313041
/// If a local event's origin matches the given prefix, it will not be recorded in the
30323042
/// undo stack.
30333043
pub fn add_exclude_origin_prefix(&mut self, prefix: &str) {

crates/loro/tests/integration_test/undo_test.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,10 @@ fn undo_id_span_that_contains_remote_deps_inside() -> Result<(), LoroError> {
302302
})
303303
);
304304
while undo_a.can_undo() {
305+
assert!(undo_a.undo_count() > 0);
305306
undo_a.undo()?;
306307
}
308+
assert_eq!(undo_a.undo_count(), 0);
307309
assert_eq!(
308310
doc_a.get_deep_value().to_json_value(),
309311
json!({
@@ -336,8 +338,10 @@ fn undo_id_span_that_contains_remote_deps_inside_many_times() -> Result<(), Loro
336338

337339
// Undo all ops from A
338340
while undo.can_undo() {
341+
assert!(undo.undo_count() > 0);
339342
undo.undo()?;
340343
}
344+
assert_eq!(undo.undo_count(), 0);
341345
assert_eq!(
342346
doc_a.get_deep_value().to_json_value(),
343347
json!({
@@ -764,6 +768,7 @@ fn collab_undo() -> anyhow::Result<()> {
764768
for j in 0..3 {
765769
debug_span!("round A", j).in_scope(|| {
766770
assert!(!undo_a.can_redo(), "{:#?}", &undo_a);
771+
assert_eq!(undo_a.redo_count(), 0);
767772
assert_eq!(
768773
doc_a.get_text("text").get_richtext_value().to_json_value(),
769774
json!([
@@ -774,6 +779,7 @@ fn collab_undo() -> anyhow::Result<()> {
774779
);
775780
undo_a.undo()?;
776781
assert!(undo_a.can_redo());
782+
assert_eq!(undo_a.redo_count(), 1);
777783
assert_eq!(
778784
doc_a.get_text("text").get_richtext_value().to_json_value(),
779785
json!([
@@ -798,6 +804,8 @@ fn collab_undo() -> anyhow::Result<()> {
798804
);
799805

800806
assert!(!undo_a.can_undo());
807+
assert_eq!(undo_a.undo_count(), 0);
808+
assert!(undo_a.redo_count() > 0);
801809
undo_a.redo()?;
802810
assert_eq!(
803811
doc_a.get_text("text").get_richtext_value().to_json_value(),
@@ -806,6 +814,7 @@ fn collab_undo() -> anyhow::Result<()> {
806814
])
807815
);
808816

817+
assert!(undo_a.redo_count() > 0);
809818
undo_a.redo()?;
810819
assert_eq!(
811820
doc_a.get_text("text").get_richtext_value().to_json_value(),
@@ -815,6 +824,7 @@ fn collab_undo() -> anyhow::Result<()> {
815824
{"insert": " fox jumped."}
816825
])
817826
);
827+
assert!(undo_a.redo_count() > 0);
818828
undo_a.redo()?;
819829
Ok::<(), LoroError>(())
820830
})?;
@@ -859,7 +869,9 @@ fn collab_undo() -> anyhow::Result<()> {
859869
])
860870
);
861871
assert!(!undo_b.can_undo());
872+
assert_eq!(undo_b.undo_count(), 0);
862873
assert!(undo_b.can_redo());
874+
assert!(undo_b.redo_count() > 0);
863875
undo_b.redo()?;
864876
assert_eq!(
865877
doc_b.get_text("text").get_richtext_value().to_json_value(),
@@ -1360,6 +1372,7 @@ fn undo_list_move() -> anyhow::Result<()> {
13601372
doc.commit();
13611373
for _ in 0..3 {
13621374
assert!(!undo.can_redo());
1375+
assert_eq!(undo.redo_count(), 0);
13631376
assert_eq!(
13641377
doc.get_deep_value().to_json_value(),
13651378
json!({
@@ -1368,6 +1381,7 @@ fn undo_list_move() -> anyhow::Result<()> {
13681381
);
13691382
undo.undo()?;
13701383
assert!(undo.can_redo());
1384+
assert!(undo.redo_count() > 0);
13711385
assert_eq!(
13721386
doc.get_deep_value().to_json_value(),
13731387
json!({
@@ -1392,24 +1406,31 @@ fn undo_list_move() -> anyhow::Result<()> {
13921406
undo.undo()?;
13931407
undo.undo()?;
13941408
assert!(!undo.can_undo());
1409+
assert_eq!(undo.undo_count(), 0);
1410+
assert!(undo.redo_count() > 0);
13951411
undo.redo()?;
13961412
assert!(undo.can_undo());
1413+
assert!(undo.undo_count() > 0);
1414+
assert!(undo.redo_count() > 0);
13971415
undo.redo()?;
13981416

1417+
assert!(undo.redo_count() > 0);
13991418
undo.redo()?;
14001419
assert_eq!(
14011420
doc.get_deep_value().to_json_value(),
14021421
json!({
14031422
"list": ["0", "1", "2"]
14041423
})
14051424
);
1425+
assert!(undo.redo_count() > 0);
14061426
undo.redo()?;
14071427
assert_eq!(
14081428
doc.get_deep_value().to_json_value(),
14091429
json!({
14101430
"list": ["1", "2", "0"]
14111431
})
14121432
);
1433+
assert!(undo.redo_count() > 0);
14131434
undo.redo()?;
14141435
assert_eq!(
14151436
doc.get_deep_value().to_json_value(),
@@ -1418,6 +1439,7 @@ fn undo_list_move() -> anyhow::Result<()> {
14181439
})
14191440
);
14201441
assert!(!undo.can_redo());
1442+
assert_eq!(undo.redo_count(), 0);
14211443
}
14221444
Ok(())
14231445
}
@@ -1484,6 +1506,7 @@ fn exclude_certain_local_ops_from_undo() -> anyhow::Result<()> {
14841506
})
14851507
);
14861508
assert!(!undo.can_undo());
1509+
assert_eq!(undo.undo_count(), 0);
14871510
undo.redo()?;
14881511
assert_eq!(
14891512
doc.get_deep_value().to_json_value(),

0 commit comments

Comments
 (0)