Commit Graph
14 Commits
Author SHA1 Message Date
prxnvt 57d7ea9bc3 Engine: a Python reference that grows or shrinks drops the cell's kept result
Deleting part of a range that xl() reads (row 2 of A1:A3) shortens the
reference instead of making it #REF!, and inserting rows inside the range
lengthens it; either way the data the code reads changed, but the cell kept
its result. rewrite_python_refs now treats a reference whose rows or columns
changed in number like a deleted one: the cell is new code (#BLOCKED!) with no
kept result. A reference that only moves keeps the result.

Test: deleting_the_data_python_code_reads_drops_its_kept_result now covers a
partial deletion and an insertion inside the range (fails without the fix).
2026-11-02 02:52:38 -05:00
prxnvt e8f2becf4a Engine: a deleted reference drops a Python cell's kept result; spills read past the scan budget stay values
A structural edit that deleted the data an xl() reference names rewrote the
reference to #REF! but kept the cell's cached result, so the cell went on
showing a result for data that is gone. rewrite_python_refs now makes such a
cell new code (#BLOCKED!, no kept result), and the recalculation removes its
spill. A rename or a move, after which the reference names the same data,
still keeps the result.

When the reader's range-scan budget ran out part way through a Python spill,
the rest of its cells were read as plain cells, and the result rebuilt on open
was then blocked by them (#SPILL!). On such a sheet every Python spill now
keeps its values as plain values, with no live spill.

Tests: deleting_the_data_python_code_reads_drops_its_kept_result and
python_spills_read_past_the_scan_budget_keep_their_values_as_plain_values;
both fail without the fix.
2026-11-02 02:27:28 -05:00
prxnvt 52b00fe8f8 Engine: an edit that would make Python code too long is refused
Structural edits, sheet renames and deletes, and a cut to another sheet
rewrite the xl() references in Python code, and could make a cell's code
longer than the 8,192-character limit that python.set enforces. Opening the
saved file then dropped that code to its value. Such an edit is now refused
with a message naming the cell, and nothing changes; keeping the old text
would have left a reference the edit had moved.
2026-11-01 15:35:54 -05:00
prxnvt 11b55e0c71 Calc: new Python code recalculates the readers of the cell's old spill
python.set, and Replace in a Python cell's code, removed the cell's spill
registration and its spilled values before the recalculation ran, so the
recalculation never saw the freed range and formulas reading those cells kept
their old values until a full recalculation. The commands now leave the spill
to the recalculation. When a Python cell's content changes and it has no array
result to lay out, cells_changed removes the spill and queues the freed range,
as it does for a formula replaced by a constant, so its readers are
recalculated; a cell that keeps its array result (the same code again) keeps
its spill and lays it out again. Clearing, pasting over and blocking a Python
spill already recalculated its readers, and undo and redo restore the values
along with the cells; a test covers them.
2026-11-01 14:41:48 -05:00
prxnvt b3a3590db6 Merge main into Python cells as data 2026-11-01 14:03:09 -05:00
FredApps 10b763e7a4 Merge current main into PR467 and preserve both documentation histories 2026-11-01 19:06:22 +01:00
Brandon ThomasandClaude Opus 5.5 ea1d52fe8f Review fixes for #3042: "" with parse: false keeps the cell's formatting; correct the write_range parse description
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 12:20:54 -05:00
prxnvt 14ab0f8ee3 Engine: Replace edits a Python cell's code and keeps it a Python cell
Replace matched a Python cell on its code and then rebuilt the cell from the
replaced text as if it had been typed, so the cell became a text cell holding
the edited code and the Python cell was lost. The replacement now edits the
code: the cell stays a Python cell with its return type, its result is dropped
(#BLOCKED!, as for any changed code) and a spill it had is cleared. Code that
would no longer fit in a PY formula is left unchanged and counted in a new
skipped field of the result.
2026-11-01 12:10:31 -05:00
prxnvt c03c61fd05 Merge main into Python cells as data 2026-11-01 12:00:09 -05:00
Max Murphy 8fff311210 range.setValues: report the strings typed input read, and clear "" with parse: false (#2255)
The default still reads a string with typed input, which is en-US: "05.04.2026"
from a dd.mm.yyyy export became 4 May, "2.500" became 2.5, and the command said
nothing (#2255). `parse: false` (PR #2267) lets a caller keep the text, but a
script that does not pass it still cannot notice the change.

The result now names them: `converted` lists the strings typed input read as a
number (dates and times included), a boolean or an error, with the cell, the
input and what the cell shows, and `convertedCount` is the total. It is capped
at 20 entries and 32 characters per string, so a big write does not put a second
copy of its data in the result. A string written as a formula (`=1+1`) and a
leading apostrophe are not conversions. `cells` and the default reading of the
values are unchanged.

Two `parse: false` fixes from the review of #2267:

- An empty string clears the cell, as `null` and the default path do. Storing an
  empty text cell left a cell that is not blank: `values: [["", ""]]` gave
  COUNTA 2 and ISBLANK FALSE.
- MCP `write_range` takes `parse`, so an agent can opt out too; the tool's
  description and docs/mcp.md say so.

Tests: the issue's examples under both settings, the report and its cap, the
empty string, and an XLSX save/reopen that keeps the text as text and the
default's date as a date.
2026-10-31 16:57:38 +01:00
prxnvt 474472f999 Engine: Recently Used follows the formulas entered; Insert Function category list
formulas.recentlyUsed scanned the session journal for cell.set inputs.
It missed formulas entered by range.* commands, lost them when the
journal dropped its oldest entries (a large file open or a long script
is enough), and started empty in every session. The Function Library's
Recently Used menu and the Insert Function dialog list what it returns.

- Prefs::recent_functions (a new engine module, recent.rs) holds the
  ten functions most recently entered in a formula, newest first.
  Session::execute updates it for every cell.* and range.* command it
  journals, from any source (the interface, the control channel, MCP or
  a script). It reads at most 2,000 of the formulas a command enters,
  starting from the last one; formulas longer than Excel's limit are
  skipped. formulas.recentlyUsed
  returns it. It never reads the journal back, so the journal's caps do
  not affect it.
- The list is kept with the other engine preferences (prefs.json, the
  browser's storage on the web), so it survives a restart as Excel's
  does. It is read leniently: a malformed value loses only this list. A
  fresh install starts from common functions.

The Insert Function dialog is titled "Insert Function", as in Excel (it
said "Formula Builder"), and gains a working category list: Most
Recently Used, All, then each category in Excel's order. A category may
be given by label or by engine id, so a Function Library menu or the
control channel (ui.dialog.set) opens it on one, and a new search
switches to All. The dialog keeps its translated labels and its search
in the interface language. Each row shows the function's name and its
category in two columns; the category column starts after the widest
name shown, so a long name in any font or formula language stays clear
of it. A function counts as recently used once its formula is entered,
not when OK is pressed. The unused "Formula Builder" translations are
removed.

Tests: engine unit tests for reading functions from formulas (strings,
unknown names, over-long and malformed formulas), the formulas a
command enters (newest first, within the budget), the ten-name list
and the lenient read of prefs.json; tests/it/recently_used.rs for
cell.set and range.setValues from the session, a failed command, a
cleared journal and a save and reload of the preferences. UI tests for
the menu's order and the dialog's title, categories, engine-id
category, search and OK, and for the category column with a wide font.
2026-10-31 04:00:56 -04:00
Dylan M. Taylor 9717ccbac1 Refactor engine for strict Clippy checks 2026-10-28 10:52:53 +00:00
aiongg 0069d91e90 refactor(engine): move cmd/edit.rs items to cmd/edit/ 2026-10-26 20:43:39 +00:00
aiongg 2b808def4f refactor(engine): move cmd/edit tests to src/cmd/edit/tests.rs 2026-10-26 18:15:40 +00:00