mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-03 00:41:56 -06:00
UI: a draft typed over a hidden Python cell stays open
An ordinary draft typed over an unlocked, hidden Python cell on a protected sheet holds only what was typed. follow_open_draft dropped it after any command, and ui.inspect hid its text, because both checked whether the cell was a Python cell. They now check whether the draft holds code: a draft in Python mode, or one that began on a Python cell's code (py_cell). Test: a_draft_typed_over_a_hidden_python_cell_stays_open_through_commands (fails without the fix: the draft was dropped).
This commit is contained in:
@@ -220,18 +220,18 @@ impl SheetApp {
|
||||
/// drawn, pointed from and committed on its sheet, and the point-mode anchor, held by sheet
|
||||
/// index, is let go. A draft is dropped at once with a message when its sheet is gone, or when
|
||||
/// it holds Python code that sheet protection now hides (a draft in Python mode, or one that
|
||||
/// began on a Python cell): neither editor shows hidden code, as the Python editor window
|
||||
/// closes then too.
|
||||
/// began on a Python cell's code): neither editor shows hidden code, as the Python editor
|
||||
/// window closes then too. A draft typed over a Python cell holds only what was typed, so it
|
||||
/// stays open.
|
||||
pub(crate) fn follow_open_draft(&mut self) {
|
||||
let Some(ed) = self.editor.as_ref() else { return };
|
||||
let Some(d) = self.session.documents().iter().find(|d| d.uid == ed.doc) else { return };
|
||||
let order = editor::sheet_order(&d.wb);
|
||||
let moved = ed.sheet_uid != 0 && order != ed.sheet_order;
|
||||
let found = if moved { ed.sheet_in(&d.wb) } else { Some(ed.sheet) };
|
||||
let hidden = found.and_then(|i| d.wb.sheet(i)).is_some_and(|sh| {
|
||||
(ed.python || ed.py_cell || sh.cell(ed.cell).is_some_and(|c| c.py.is_some()))
|
||||
&& gridcraft_engine::display::formula_hidden(&d.wb, sh, ed.cell)
|
||||
});
|
||||
let hidden = found
|
||||
.and_then(|i| d.wb.sheet(i))
|
||||
.is_some_and(|sh| (ed.python || ed.py_cell) && gridcraft_engine::display::formula_hidden(&d.wb, sh, ed.cell));
|
||||
let why = match found {
|
||||
None => Some(DRAFT_SHEET_GONE),
|
||||
Some(_) if hidden => Some(DRAFT_CODE_HIDDEN),
|
||||
|
||||
@@ -161,16 +161,18 @@ pub fn inspect(app: &SheetApp, ctx: &egui::Context) -> Json {
|
||||
|
||||
/// The open edit, for `ui.inspect`. The draft is left out (`text` is null, `hidden` true) while
|
||||
/// its cell's code is hidden on a protected sheet, checked now: a protection command earlier in
|
||||
/// the same batch runs before the next frame. That holds for a draft in Python mode, and for any
|
||||
/// draft of a Python cell, since leaving Python mode keeps the code as an ordinary draft. The
|
||||
/// sheet is the draft's own, found by identity: a sheet inserted, deleted or moved in the same
|
||||
/// batch puts another at its index. With its sheet gone, such a draft is left out too.
|
||||
/// the same batch runs before the next frame. That holds for a draft in Python mode, and for a
|
||||
/// draft that began on a Python cell's code, since leaving Python mode keeps the code as an
|
||||
/// ordinary draft; a draft typed over a Python cell holds only what was typed. The sheet is the
|
||||
/// draft's own, found by identity: a sheet inserted, deleted or moved in the same batch puts
|
||||
/// another at its index. With its sheet gone, such a draft is left out too.
|
||||
fn editor_json(app: &SheetApp, e: &crate::editor::EditState) -> Json {
|
||||
let code = |sh: &gridcraft_engine::model::Sheet| e.python || sh.cell(e.cell).is_some_and(|c| c.py.is_some());
|
||||
let hidden = app.session.documents().iter().find(|d| d.uid == e.doc).is_some_and(|d| match e.sheet_in(&d.wb).and_then(|i| d.wb.sheet(i)) {
|
||||
Some(sh) => code(sh) && gridcraft_engine::display::formula_hidden(&d.wb, sh, e.cell),
|
||||
None => e.python || e.py_cell,
|
||||
});
|
||||
let code = e.python || e.py_cell;
|
||||
let hidden = code
|
||||
&& app.session.documents().iter().find(|d| d.uid == e.doc).is_some_and(|d| match e.sheet_in(&d.wb).and_then(|i| d.wb.sheet(i)) {
|
||||
Some(sh) => gridcraft_engine::display::formula_hidden(&d.wb, sh, e.cell),
|
||||
None => true,
|
||||
});
|
||||
let text = if hidden { Json::Null } else { json!(e.text) };
|
||||
json!({"cell": e.cell.a1(), "text": text, "hidden": hidden, "formulaBar": e.from_formula_bar, "point": e.can_point(), "python": e.python})
|
||||
}
|
||||
|
||||
@@ -1208,3 +1208,28 @@ fn a_draft_of_python_code_that_protection_hides_is_dropped_with_a_message() {
|
||||
execute(&mut app, &ctx, "review.protectSheet", json!({}));
|
||||
assert!(app.editor.as_ref().is_some_and(|e| e.text == "=2+2"), "a formula draft is unchanged");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_draft_typed_over_a_hidden_python_cell_stays_open_through_commands() {
|
||||
// An unlocked, hidden Python cell on a protected sheet: typing replaces it, as in Excel. The
|
||||
// draft holds only what was typed, so a command neither drops it nor hides it from ui.inspect.
|
||||
let mut session = gridcraft_engine::Session::new();
|
||||
session.new_workbook();
|
||||
session.execute("python.set", json!({"cell": "B2", "code": "secret = 41"})).unwrap();
|
||||
session.execute("home.formatCells", json!({"range": "B2", "style": {"protection": {"hidden": true, "locked": false}}})).unwrap();
|
||||
session.execute("review.protectSheet", json!({})).unwrap();
|
||||
session.execute("selection.set", json!({"cell": "B2"})).unwrap();
|
||||
let mut app = SheetApp::new(session, crate::Services::default());
|
||||
let ctx = egui::Context::default();
|
||||
call(&mut app, &ctx, "ui.edit.begin", json!({"text": "7"}));
|
||||
execute(&mut app, &ctx, "home.insertSheet", json!({"name": "Other", "before": 1}));
|
||||
assert!(app.editor.as_ref().is_some_and(|e| e.text == "7"), "the typed entry stays open");
|
||||
assert!(app.message.is_none(), "{:?}", app.message);
|
||||
let after = inspected(&mut app, &ctx);
|
||||
assert_eq!(after["editor"]["text"], "7");
|
||||
assert_eq!(after["editor"]["hidden"], false);
|
||||
call(&mut app, &ctx, "ui.edit.commit", json!({"move": "none"}));
|
||||
let b2 = app.session.active().and_then(|d| d.wb.sheet(0)).and_then(|sh| sh.cell(gridcraft_engine::core::CellRef::new(1, 1)).cloned());
|
||||
assert_eq!(b2.map(|c| (c.input_text(), c.py.is_some())), Some(("7".to_string(), false)), "the typed entry replaces the Python cell");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user