Merge pull request #4072 from dotCooCoo/fix/recovery-threaded-continuation-marks

Type: a recovered document keeps continued paragraphs in threaded frames
This commit is contained in:
Brandon Thomas
2026-10-25 10:37:19 -04:00
committed by GitHub
2 changed files with 30 additions and 0 deletions
+3
View File
@@ -996,6 +996,9 @@ fn restore_one(s: &mut Session, store: &Arc<dyn RecoveryStore>, file: &str) -> R
let meta_bytes = store.read(&format!("{file}{META_EXT}")).unwrap_or_default();
let meta: Meta = serde_json::from_slice(&meta_bytes).unwrap_or_default();
let (mut doc, _, mut warnings) = fileio::native_file(&bytes).map_err(|e| EngineError::Other(format!("recovery copy `{file}`: {e}")))?;
// A frame whose first paragraph continues from the frame before draws it without the
// paragraph's first-line indent and list marker.
super::threads::mark_continued(&mut doc);
// The images, from the entries of the copy's area.
let from = file.split_once('/').map_or("", |(a, _)| a);
let mut blobs = vec![];
+27
View File
@@ -138,6 +138,33 @@ fn a_crash_leaves_copies_that_restore_modified_and_titled() {
assert!(s.execute("file.recovery.restore", &json!({"file": format!("{mine}/Poster-1")})).is_err(), "an open document's copy");
}
/// A threaded frame whose first paragraph continues from the frame before is restored without
/// that paragraph's first-line indent.
#[test]
fn a_restored_copy_keeps_continued_paragraphs_in_threaded_frames() {
let store = Arc::new(MemoryStore::default());
let mut s = relaunch(&store);
s.execute("file.new", &json!({"width": 600, "height": 300})).unwrap();
let story = "The quick brown fox jumps over the lazy dog and keeps running far beyond the first frame of this story. ".repeat(4);
let a =
s.execute("text.create", &json!({"x": 10, "y": 10, "text": story, "area": {"width": 150, "height": 60}})).unwrap()["id"].as_u64().unwrap();
let b = s.execute("shape.rectangle", &json!({"x": 200, "y": 10, "width": 150, "height": 200})).unwrap()["id"].as_u64().unwrap();
s.execute("select.set", &json!({"ids": [a, b]})).unwrap();
s.execute("text.thread.create", &json!({})).unwrap();
s.execute("text.setFormat", &json!({"ids": [a, b], "leftIndent": 0, "firstLineIndent": 24})).unwrap();
let continues = |s: &Session| match &s.doc().unwrap().doc.node(vectorcraft_doc::NodeId(b)).unwrap().kind {
vectorcraft_doc::NodeKind::Text(t) => t.first_para_continues,
_ => panic!("not text"),
};
assert!(continues(&s));
s.execute("file.recovery.save", &json!({})).unwrap();
drop(s);
let mut s = relaunch(&store);
assert_eq!(restored(s.execute("file.recovery.restore", &json!({})).unwrap()), 1);
assert!(continues(&s), "the second frame continues the first frame's paragraph");
}
#[test]
fn a_restored_copy_still_refuses_to_replace_the_file_an_import_left_things_out_of() {
let (mut s, store) = session();