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:
vangel76
2026-10-14 22:56:36 +02:00
co-authored by Claude Sonnet 5.5
parent d9d09f0baa
commit 833fe0da1f
3 changed files with 50 additions and 0 deletions
+1
View File
@@ -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) |
+26
View File
@@ -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() {
+23
View File
@@ -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");
}