mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Edit: text that would parse as a number or formula keeps its quote prefix in the editor (#1362)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
d9d09f0baa
commit
833fe0da1f
@@ -21,6 +21,7 @@ This page is the summary. The detail is in:
|
||||
|
||||
| Number | Value | Kind |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | Editing a cell with text that would read back as a number, boolean, date or formula (entered with a leading apostrophe) shows the apostrophe in the editor and formula bar, so Enter unchanged keeps it text (#1362) |
|
||||
| **Feature breadth** (weighted) | **~75%** | estimated, anchored on two measurements: ribbon catalog 274 / 290 (94.5%), worksheet functions 513 / 523 (98.1%; 504 working, 96.4%) |
|
||||
| **Ready for real work** | **~50%** | estimated from written weights (51.6); [target-app-parity.md](docs/target-app-parity.md) |
|
||||
| **Mainstream practitioner** | **~50%** | estimated: typical analyst/finance user, weekly features, × 0.90 interaction × 0.92 stability × 0.88 file exchange; [method](docs/target-app-parity.md#mainstream-practitioner) |
|
||||
|
||||
@@ -33,6 +33,25 @@ pub fn format(v: &Value, code: &str, wb: &Workbook) -> Formatted {
|
||||
format_value(v, &parsed(code), wb.date_system)
|
||||
}
|
||||
|
||||
/// Whether typing `t` back into a General cell would not give the text `t` again (it would parse
|
||||
/// as a number, boolean, error, date or formula, or lose a leading apostrophe). Such text is shown
|
||||
/// for editing with a leading `'`, as Excel does for text carrying a quote prefix, so that
|
||||
/// committing the editor unchanged keeps the cell as text.
|
||||
fn text_needs_quote_prefix(t: &str, sys: gridcraft_core::date::DateSystem) -> bool {
|
||||
if t.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let mut chars = t.chars();
|
||||
let (first, second) = (chars.next(), chars.next());
|
||||
if matches!(first, Some('=' | '\'')) {
|
||||
return true;
|
||||
}
|
||||
if matches!(first, Some('+' | '-')) && second.is_some_and(|c| c.is_ascii_alphabetic() || c == '(') {
|
||||
return true;
|
||||
}
|
||||
!matches!(gridcraft_core::parse::parse_input(t, sys).value, Value::Text(ref x) if x.as_ref() == t)
|
||||
}
|
||||
|
||||
/// What the cell editor and the formula bar start from. Same as `Cell::input_text`, except that a
|
||||
/// constant number in a date or time format is shown as a date (as the grid shows it), not as its
|
||||
/// serial. When the formatted text would not read back as the same date (for example
|
||||
@@ -41,6 +60,13 @@ pub fn format(v: &Value, code: &str, wb: &Workbook) -> Formatted {
|
||||
pub fn edit_text(wb: &Workbook, sheet: &Sheet, c: CellRef) -> String {
|
||||
let raw = sheet.input_text(c);
|
||||
let Some(cell) = sheet.cell(c) else { return raw };
|
||||
if let Value::Text(t) = &cell.value
|
||||
&& cell.formula.is_none()
|
||||
&& wb.styles.get(cell.style).num_fmt.as_str() != "@"
|
||||
&& text_needs_quote_prefix(t, wb.date_system)
|
||||
{
|
||||
return format!("'{raw}");
|
||||
}
|
||||
let Value::Number(n) = &cell.value else { return raw };
|
||||
let code = wb.styles.get(cell.style).num_fmt.as_str();
|
||||
if cell.formula.is_some() || !parsed(code).is_date() {
|
||||
|
||||
@@ -3282,3 +3282,26 @@ fn paste_special_validation_moves_relative_references() {
|
||||
assert!(!ok(&mut s, "C3", "5"), "the pasted rule checks C3, not A1");
|
||||
assert!(ok(&mut s, "C3", "20"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editing_quote_prefixed_text_keeps_it_text() {
|
||||
let mut s = s();
|
||||
for (i, input) in ["'00123", "'=1+1", "'TRUE", "''abc"].iter().enumerate() {
|
||||
let cell = format!("A{}", i + 1);
|
||||
s.execute("cell.set", json!({"cell": cell, "input": input})).unwrap();
|
||||
let at = CellRef::parse(&cell).unwrap();
|
||||
let before = v(&s, &cell);
|
||||
let edit = {
|
||||
let d = s.doc().unwrap();
|
||||
crate::display::edit_text(&d.wb, d.wb.active().unwrap(), at)
|
||||
};
|
||||
assert_eq!(&edit, input, "edit text of {cell}");
|
||||
// Committing the editor unchanged leaves the cell as it was.
|
||||
s.execute("cell.set", json!({"cell": cell, "input": edit})).unwrap();
|
||||
assert_eq!(v(&s, &cell), before, "{cell}");
|
||||
}
|
||||
// Plain text is shown as typed, without a prefix.
|
||||
s.execute("cell.set", json!({"cell": "B1", "input": "hello"})).unwrap();
|
||||
let d = s.doc().unwrap();
|
||||
assert_eq!(crate::display::edit_text(&d.wb, d.wb.active().unwrap(), CellRef::parse("B1").unwrap()), "hello");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user