mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Paste Special operations: keep text, errors and formulas
Add, Subtract, Multiply and Divide replaced every cell that didn't hold a plain number with the pasted value: multiplying a column by 1 turned numbers stored as text, headers and #N/A all into 1, and a formula into a constant. As in Excel, numbers stored as text now take part (the usual way to turn them into numbers), other text and errors stay, and a formula is kept and combined with the pasted number: =(B3*2)*1.
This commit is contained in:
@@ -868,8 +868,10 @@ fn paste_special(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
{
|
||||
let a = old.value.clone();
|
||||
let b = new.value.clone();
|
||||
// Numbers stored as text take part (multiplying by 1 turns them into
|
||||
// numbers); other text and errors stay as they are.
|
||||
if let (Ok(x), Ok(y)) = (a.to_number(), b.to_number())
|
||||
&& (a.is_number() || a.is_empty())
|
||||
&& (a.is_number() || a.is_empty() || a.is_text())
|
||||
&& (b.is_number() || b.is_empty())
|
||||
{
|
||||
new.value = match op.as_str() {
|
||||
@@ -883,8 +885,26 @@ fn paste_special(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
Value::number(x / y)
|
||||
}
|
||||
}
|
||||
_ => b,
|
||||
_ => b.clone(),
|
||||
};
|
||||
} else if (a.is_text() || a.is_error()) && (b.is_number() || b.is_empty()) {
|
||||
new.value = a;
|
||||
}
|
||||
// A formula already there is kept and combined with the pasted number.
|
||||
if let Some(f) = &old.formula
|
||||
&& let Ok(y) = b.to_number()
|
||||
&& (b.is_number() || b.is_empty())
|
||||
&& let Some(sym) = match op.as_str() {
|
||||
"add" => Some('+'),
|
||||
"subtract" => Some('-'),
|
||||
"multiply" => Some('*'),
|
||||
"divide" => Some('/'),
|
||||
_ => None,
|
||||
}
|
||||
{
|
||||
let text = format!("=({}){sym}{}", f.text, gridcraft_core::number_to_text(y));
|
||||
new.formula = Some(std::sync::Arc::new(Formula::new(&text)));
|
||||
new.value = Value::Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1327,6 +1347,28 @@ mod tests {
|
||||
assert_eq!(parse_tsv("\"he said \"\"hi\"\"\""), vec![vec!["he said \"hi\""]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paste_special_operations_keep_text_errors_and_formulas() {
|
||||
let mut s = Session::new();
|
||||
s.new_workbook();
|
||||
s.execute(
|
||||
"range.setValues",
|
||||
json!({"range": "A1", "values": [["'123", "Total", "=NA()", "=B3*2", 5], [1, null, null, null, null], [null, 4, null, null, null]]}),
|
||||
)
|
||||
.unwrap();
|
||||
let get = |s: &mut Session, a: &str| s.execute("cell.get", json!({"cell": a})).unwrap();
|
||||
assert_eq!(get(&mut s, "A1")["value"], "123");
|
||||
s.execute("edit.copy", json!({"range": "A2"})).unwrap();
|
||||
s.execute("selection.set", json!({"range": "A1:E1"})).unwrap();
|
||||
s.execute("edit.pasteSpecial", json!({"what": "values", "operation": "multiply"})).unwrap();
|
||||
assert_eq!(get(&mut s, "A1")["value"], json!(123.0));
|
||||
assert_eq!(get(&mut s, "B1")["value"], "Total");
|
||||
assert_eq!(get(&mut s, "C1")["value"]["error"], "#N/A");
|
||||
assert_eq!(get(&mut s, "D1")["formula"], "=(B3*2)*1");
|
||||
assert_eq!(get(&mut s, "D1")["value"], json!(8.0));
|
||||
assert_eq!(get(&mut s, "E1")["value"], json!(5.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_case_insensitive() {
|
||||
assert_eq!(replace_ci("Apple apple APPLE", "apple", "pear"), "pear pear pear");
|
||||
|
||||
Reference in New Issue
Block a user