authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-03 22:26:54-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-03 22:37:36-07:00
logaff2de64c7f950b0e204e4c3e7e094e644847f4d
tree9a7a1381b150f45534082e3cfcc47142496739de
parentfa491ad643baacd44b828f5da2fc401bf098334a
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU

fix: restore the whole outline after cutting its only picture

Keep the empty text paragraph when reconstructing an emptied outline for Undo. Cover Cut, Undo, Redo, and Undo on a lone inline picture. Refs #80 Assisted-by: gpt-6.1-sol

1 files changed, 30 insertions(+), 2 deletions(-)

crates/canvas/src/editor.rs+30-2
...@@ -4855,9 +4855,10 @@ impl CanvasEditor {...@@ -4855,9 +4855,10 @@ impl CanvasEditor {
4855 };4855 };
4856 let outline = self.outlines.remove(index);4856 let outline = self.outlines.remove(index);
4857 self.record(Ok(vec![PageOp::Delete { object: outline.id }]));4857 self.record(Ok(vec![PageOp::Delete { object: outline.id }]));
4858 debug_assert_eq!(change.edit.range, 0..1);
4859 let mut source = outline.snapshot();4858 let mut source = outline.snapshot();
4860 source.paragraphs = change.edit.replacement;4859 source
4860 .paragraphs
4861 .splice(change.edit.range, change.edit.replacement);
4861 self.undo.push(History::Restore {4862 self.undo.push(History::Restore {
4862 index,4863 index,
4863 source: Box::new(source),4864 source: Box::new(source),
...@@ -6496,6 +6497,33 @@ mod tests {...@@ -6496,6 +6497,33 @@ mod tests {
6496 }6497 }
6497 }6498 }
64986499
6500 #[test]
6501 fn cutting_the_only_picture_restores_its_empty_text_paragraph_on_undo() {
6502 let mut engine = TextEngine::default();
6503 let document =
6504 TextDocument::new(vec![Paragraph::new(String::new(), Format::default())]).unwrap();
6505 let mut editor = CanvasEditor::new(&mut engine, document, 240.0).unwrap();
6506 editor
6507 .create_outline(&mut engine, [36.0, 36.0], 240.0)
6508 .unwrap();
6509 let image = picture(
6510 include_bytes!("../../../corpus/object-tags/native/notebook/photo.png").to_vec(),
6511 [40.0, 30.0],
6512 )
6513 .unwrap();
6514 let id = image.id;
6515 editor.insert_picture(&mut engine, image).unwrap();
6516 editor.remove_image(&mut engine, id).unwrap();
6517 assert!(editor.active_outline().is_empty());
6518 assert!(editor.undo(&mut engine).unwrap());
6519 assert!(editor.image_placement(id).is_some());
6520 assert_eq!(editor.active_outline().document.nodes().len(), 2);
6521 assert!(editor.redo(&mut engine).unwrap());
6522 assert!(editor.active_outline().is_empty());
6523 assert!(editor.undo(&mut engine).unwrap());
6524 assert!(editor.image_placement(id).is_some());
6525 }
6526
6499 #[test]6527 #[test]
6500 fn pictures_move_and_resize_through_history_and_backgrounds_stay_put() {6528 fn pictures_move_and_resize_through_history_and_backgrounds_stay_put() {
6501 use onestore::page::{Image, Page, PageObject};6529 use onestore::page::{Image, Page, PageObject};