#1537: review — a browser's Mod+Shift+V paste event pastes text only, once (CodeRabbit)

On the web the key no longer pastes as well: the paste event that follows carries the text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Martin Ball
2026-11-05 00:24:14 +00:00
co-authored by Claude Opus 5.5
parent 30ee8bb450
commit 43d9542c3d
3 changed files with 27 additions and 1 deletions
+3
View File
@@ -510,9 +510,12 @@ fn handle_event(app: &mut WordApp, ctx: &egui::Context, e: egui::Event) {
egui::Event::Paste(t) => {
// Mod+Alt+V arrives as a paste too (the shell reads the clipboard): Paste Special.
let m = ctx.input(|i| i.modifiers);
// A browser sends Mod+Shift+V as a paste too: Keep Text Only, as the key does on the
// desktop (#1537). (egui-winit sends that chord as a key, and Shift+Insert has no Mod.)
let id = match (m.alt, m.shift) {
(true, true) => "edit.pasteText",
(true, false) => "edit.pasteSpecial",
(false, true) if m.command => "edit.pasteText",
_ => "edit.paste",
};
let _ = app.run(id, json!({"text": t}));
+9 -1
View File
@@ -134,7 +134,15 @@ pub(super) fn dispatch(app: &mut WordApp, key: Key, m: Modifiers) -> bool {
}
// Mod+Shift+V pastes the formatting Mod+Shift+C picked up; with none picked up it pastes
// the clipboard as text only, as Word for Windows does (#1537, #4943).
let id = if spec.id == "edit.pasteFormat" && app.session.painter.is_none() { "edit.pasteText" } else { spec.id };
let id = if spec.id == "edit.pasteFormat" && app.session.painter.is_none() {
// On the web the browser's paste event that follows carries the text: paste once, there.
if cfg!(target_arch = "wasm32") {
return true;
}
"edit.pasteText"
} else {
spec.id
};
let _ = app.run(id, json!({}));
return true;
}
+15
View File
@@ -133,6 +133,21 @@ fn only_plain_paste_releases_paste_a_clipboard_picture() {
assert!(!is_paste_special_release(Key::V, m(true, true, true)) && !is_paste_special_release(Key::V, m(true, false, false)));
}
/// #1537: a browser sends Mod+Shift+V as a paste event; it pastes text only, in the destination's
/// formatting, though the clipboard also holds bold HTML. Plain Mod+V keeps the HTML's bold.
#[test]
fn a_mod_shift_paste_event_keeps_text_only() {
for (modifiers, bold) in [(Modifiers::COMMAND | Modifiers::SHIFT, false), (Modifiers::COMMAND, true)] {
let services = crate::Services { clipboard_html: Some(Box::new(|| Some("<p><b>external</b></p>".into()))), ..Default::default() };
let mut a = WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::new()), services);
let ctx = egui::Context::default();
mods_frame(&ctx, &mut a, modifiers, vec![egui::Event::Paste("external".into())]);
assert_eq!(a.session.doc.plain_text(wordcraft_doc::StoryRef::Body), "external", "{modifiers:?}");
let state = a.session.run("format.state", &json!({})).unwrap();
assert_eq!(state.get("bold").and_then(serde_json::Value::as_bool) == Some(true), bold, "{modifiers:?}: {state}");
}
}
/// An empty document whose clipboard holds a 4 × 4 picture.
fn picture_app() -> WordApp {
use crate::paste_picture::ClipboardPicture;