UI: Cmd/Ctrl+V doesn't re-paste a pasted cut's clipboard text either
This commit is contained in:
parent
fd1ed6649b
commit
4d654c5185
|
|
@ -409,9 +409,16 @@ impl SheetApp {
|
|||
ctx.copy_text(text.to_string());
|
||||
}
|
||||
|
||||
/// Paste text that came from the system clipboard, with the clipboard's HTML flavour when the
|
||||
/// host can read it.
|
||||
/// Paste text that came from the system clipboard (Cmd/Ctrl+V, or the ribbon and menu Paste),
|
||||
/// with the clipboard's HTML flavour when the host can read it.
|
||||
///
|
||||
/// Excel pastes a cut once: after GridCraft's cut has been pasted, the system clipboard text
|
||||
/// that came with it is not pasted again over the moved block; GridCraft's own (empty)
|
||||
/// clipboard is pasted instead, which reports "Nothing to paste.".
|
||||
pub fn paste_external(&mut self, text: String) {
|
||||
if self.session.clipboard.is_none() && Self::same_clipboard_text(Some(&text), self.cut_text.as_deref()) {
|
||||
return self.run_or_alert("edit.paste", json!({}));
|
||||
}
|
||||
let html = self.services.paste_html.as_mut().and_then(|read| read());
|
||||
let params = match html {
|
||||
Some(html) => json!({"text": text, "html": html}),
|
||||
|
|
@ -423,16 +430,9 @@ impl SheetApp {
|
|||
/// Ribbon and menu Paste: paste the text on the system clipboard, as Cmd/Ctrl+V does. With no
|
||||
/// text there, no host clipboard (web), or the text that was there when GridCraft last copied
|
||||
/// without publishing, GridCraft's own clipboard is pasted.
|
||||
///
|
||||
/// Excel pastes a cut once: after GridCraft's cut has been pasted, the system clipboard text
|
||||
/// that came with it is not pasted again over the moved block.
|
||||
pub fn paste_from_clipboard(&mut self) {
|
||||
let text = self.system_clipboard_text();
|
||||
let cut_pasted = self.session.clipboard.is_none() && Self::same_clipboard_text(text.as_deref(), self.cut_text.as_deref());
|
||||
match text {
|
||||
Some(text) if !cut_pasted && (self.session.clipboard.is_none() || self.clipboard_text_at_copy.as_ref() != Some(&text)) => {
|
||||
self.paste_external(text)
|
||||
}
|
||||
match self.system_clipboard_text() {
|
||||
Some(text) if self.session.clipboard.is_none() || self.clipboard_text_at_copy.as_ref() != Some(&text) => self.paste_external(text),
|
||||
_ => self.run_or_alert("edit.paste", json!({})),
|
||||
}
|
||||
}
|
||||
|
|
@ -444,10 +444,13 @@ impl SheetApp {
|
|||
}
|
||||
|
||||
/// Whether two clipboard texts are the same copy: trailing line breaks don't count, as in the
|
||||
/// engine's `edit.paste`.
|
||||
/// engine's `edit.paste`, and CRLF matches LF (egui's `Event::Paste` text may keep the host's).
|
||||
fn same_clipboard_text(a: Option<&str>, b: Option<&str>) -> bool {
|
||||
fn chars(t: &str) -> impl Iterator<Item = char> + '_ {
|
||||
t.trim_end_matches(['\r', '\n']).chars().filter(|c| *c != '\r')
|
||||
}
|
||||
match (a, b) {
|
||||
(Some(a), Some(b)) => a.trim_end_matches(['\r', '\n']) == b.trim_end_matches(['\r', '\n']),
|
||||
(Some(a), Some(b)) => chars(a).eq(chars(b)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,3 +394,37 @@ fn the_paste_keytip_pastes_the_system_clipboard_like_the_paste_button() {
|
|||
assert_eq!(value_at(&h, "E4"), Some(Value::number(7.0)));
|
||||
assert!(h.state().toast.is_none() && h.state().message.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_v_after_a_pasted_cut_does_not_paste_the_cut_text_again() {
|
||||
// Cmd/Ctrl+V hands the app the system clipboard's text, which still holds the cut after the
|
||||
// move. Excel pastes a cut once: the second Cmd/Ctrl+V must leave the moved formulas alone.
|
||||
let mut h = harness(Services::default());
|
||||
h.state_mut().run("cell.set", json!({"cell": "B3", "input": "=B2*2"})).unwrap();
|
||||
h.state_mut().run("selection.set", json!({"range": "A1:B3"})).unwrap();
|
||||
h.input_mut().events.push(Event::Cut);
|
||||
h.step();
|
||||
let text = h
|
||||
.output()
|
||||
.platform_output
|
||||
.commands
|
||||
.iter()
|
||||
.find_map(|c| match c {
|
||||
OutputCommand::CopyText(text) => Some(text.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.expect("the cut is published");
|
||||
h.run_steps(2);
|
||||
h.state_mut().run("selection.set", json!({"cell": "D4"})).unwrap();
|
||||
h.input_mut().events.push(Event::Paste(text.clone()));
|
||||
h.run_steps(2);
|
||||
assert!(has_formula(&h, "E6"), "the cut moves the formula");
|
||||
|
||||
// The host may hand the text back with CRLF line endings.
|
||||
h.input_mut().events.push(Event::Paste(text.replace('\n', "\r\n")));
|
||||
h.run_steps(2);
|
||||
assert!(has_formula(&h, "E6"), "a second Cmd/Ctrl+V leaves the moved formula alone");
|
||||
assert_eq!(value_at(&h, "E6"), Some(Value::number(84.0)));
|
||||
assert_eq!(value_at(&h, "D4"), Some(Value::from("Name")));
|
||||
assert!(h.state().toast.is_some() || h.state().message.is_some(), "Paste reports there is nothing to paste");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.
|
|||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-12 | minor | Paste from the ribbon (button and options menu), the cell and header context menus and the macOS menu bar's Edit menu pastes what is on the system clipboard, as Cmd/Ctrl+V does, instead of only GridCraft's own copy (the web build, which can't read the clipboard on request, still pastes GridCraft's copy). Copy and Cut by keytip (H,C / H,X) publish to the system clipboard like the ribbon buttons. After a control-channel or MCP copy, which leaves the system clipboard alone, Paste pastes that copy until other text is copied. Once a cut has been pasted, Paste doesn't paste the cut's clipboard text again over the moved cells (Excel pastes a cut once), and the Paste keytip (H,V,P) pastes the system clipboard like the button. Regression test for the Paste button click freeze in 0.5.0 (#273, fixed by #272); the Paste button gets an accessible "Paste" name for screen readers |
|
||||
| 2026-10-12 | minor | Paste from the ribbon (button and options menu), the cell and header context menus and the macOS menu bar's Edit menu pastes what is on the system clipboard, as Cmd/Ctrl+V does, instead of only GridCraft's own copy (the web build, which can't read the clipboard on request, still pastes GridCraft's copy). Copy and Cut by keytip (H,C / H,X) publish to the system clipboard like the ribbon buttons. After a control-channel or MCP copy, which leaves the system clipboard alone, Paste pastes that copy until other text is copied. Once a cut has been pasted, Paste (ribbon, menus or Cmd/Ctrl+V) doesn't paste the cut's clipboard text again over the moved cells (Excel pastes a cut once), and the Paste keytip (H,V,P) pastes the system clipboard like the button. Regression test for the Paste button click freeze in 0.5.0 (#273, fixed by #272); the Paste button gets an accessible "Paste" name for screen readers |
|
||||
| 2026-10-11 | minor | AutoFit accounts for table and ordinary filter dropdowns, including low zoom; header text excludes the button area |
|
||||
| 2026-10-11 | minor | Outline band for grouped rows and columns, Show / Hide Detail on the Data tab, numpad navigation keys in shortcuts (#373) |
|
||||
| 2026-10-11 | minor | Shift+Space / Ctrl+Space no longer start an edit; Control+Space selects the column on Mac (#338) |
|
||||
|
|
|
|||
Loading…
Reference in New Issue