From 9916857dba7dad886c7b5fe80742995cc121193b Mon Sep 17 00:00:00 2001 From: Hamza Date: Fri, 6 Nov 2026 17:19:35 +0500 Subject: [PATCH] Type: pin that a Type-range paste into new point type keeps its formatting #5929 reports that a styled word copied with the Type tool loses its formatting when pasted into a new point type object made by a Type tool click (placeholder text selected): on 0.21.1 the Copy left plain text on the system clipboard, so the paste could not match it with the copied runs. #5636 (on main since 0.21.1) publishes the copy through the clipboard publisher, and the paste keeps the runs. This test pins that case end to end through the app: copy, two clicks (end editing, place new type), paste, then font, size and colour of the new text. Closes #5929 --- crates/ui-egui/src/tests/clipboard.rs | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crates/ui-egui/src/tests/clipboard.rs b/crates/ui-egui/src/tests/clipboard.rs index 77ff0149b..d3b0c25a6 100644 --- a/crates/ui-egui/src/tests/clipboard.rs +++ b/crates/ui-egui/src/tests/clipboard.rs @@ -581,3 +581,42 @@ fn type_range_copy_stays_styled_when_pasted_as_art() { assert_eq!(t.runs[0].style.fill, Paint::solid(Color::rgb8(0, 255, 0))); assert_eq!(t.runs[0].style.style_name.as_deref(), Some("Emphasis")); } + +/// #5929: a styled Type-range Copy pasted into a new point type object made by a Type tool click +/// (placeholder text selected) keeps its font, size and colour, and replaces the placeholder: the +/// paste takes the copied runs, not the new object's default style. +#[test] +fn a_type_range_paste_into_new_point_type_keeps_its_formatting() { + let _guard = TEST_CLIP_LOCK.lock().unwrap(); + let (mut app, board) = super::sysclip::app(); + let source = run( + &mut app, + "text.create", + json!({"x": 20, "y": 40, "text": "Hello world", "font": "Source Serif 4", "size": 28, "color": "#00ff00"}), + )["id"] + .as_u64() + .unwrap(); + let view = app.view_info(); + app.session.select_tool("type", view).unwrap(); + app.session.set_tool_option("textSelection", &json!({"id": source, "start": 0, "end": 5})); + crate::panels::character::intercept_text_command(&mut app, "edit.copy"); + crate::background::wait_all(&mut app); + assert!(super::sysclip::written(&board).contains(&vectorcraft_engine::cmd::clipboard::TEXT)); + // The first click ends editing the source; the second places new point type with its + // placeholder text selected. + for _ in 0..2 { + for kind in [vectorcraft_tools::PointerKind::Down, vectorcraft_tools::PointerKind::Up] { + app.session.pointer(&vectorcraft_tools::PointerEvent::new(kind, 300.0, 250.0), view).unwrap(); + } + } + let fresh = app.session.tool_options()["editing"].as_u64().expect("editing new point type"); + assert_ne!(fresh, source); + crate::panels::character::intercept_text_command(&mut app, "edit.paste"); + app.session.select_tool("selection", view).unwrap(); + let node = app.session.active().unwrap().doc.node(NodeId(fresh)).unwrap().clone(); + let vectorcraft_doc::NodeKind::Text(t) = &node.kind else { panic!("not text") }; + assert_eq!(t.plain_text(), "Hello", "the paste replaces the placeholder"); + assert_eq!(t.runs[0].style.font_family, "Source Serif 4"); + assert_eq!(t.runs[0].style.size, 28.0); + assert_eq!(t.runs[0].style.fill, Paint::solid(Color::rgb8(0, 255, 0))); +}